2015-07-23 11 views
6
arr = np.arange(0,11) 
slice_of_arr = arr[0:6] 
slice_of_arr[:]=99 

# slice_of_arr returns 
array([99, 99, 99, 99, 99, 99]) 
# arr returns 
array([99, 99, 99, 99, 99, 99, 6, 7, 8, 9, 10]) 

Come nell'esempio sopra riportato, non è possibile modificare direttamente il valore di slice_of_arr, perché è una vista di arr, non una nuova variabile.NumPy: Perché la necessità di copiare esplicitamente un valore?

Le mie domande sono:

  1. Perché il design NumPy come questo? Non sarebbe noioso ogni volta che hai bisogno di .copy e poi assegnare un valore?
  2. C'è qualcosa che posso fare per liberarmi dello .copy? Come posso cambiare questo comportamento predefinito di NumPy?
+9

È progettato in questo modo per le prestazioni e l'implementazione ad es. il copy-on-write sarebbe probabilmente ancora più confuso. Perché questo design è un problema per te? – Krumelur

+0

@Krumelur Perché nella maggior parte degli scenari di programmazione non scientifica, è così che funziona. E penso che non ci sia equivalenza in 'matlab'.Devo "ricordare" questo comportamento, e in realtà non mi piace la "ripetizione" nella programmazione. – cqcn1991

+0

OK, abbastanza giusto. Immagino che sarebbe un compromesso tra la pulizia del codice che affetta le matrici e il codice, ad es. 'DoSomething (arr [6000])'. Penso che Matlab faccia CoW per risolvere questo. – Krumelur

risposta

0

What does (numpy) __array_wrap__ do?

parla ndarray sottoclassi e ganci come __array_wrap__. np.array prende il parametro copy, forzando il risultato a essere una copia, anche se non è richiesto da altre considerazioni. ravel restituisce una vista, flatten una copia. Quindi è probabilmente possibile, e forse non troppo difficile, costruire una sottoclasse ndarray che impone una copia. Potrebbe comportare la modifica di un hook come __array_wrap__.

Oppure modificare il metodo .__getitem__. L'indicizzazione come in slice_of_arr = arr[0:6] implica una chiamata a __getitem__. Per ndarray questo viene compilato, ma per un array mascherato, è il codice python che si potrebbe usare come esempio:

/usr/lib/python3/dist-packages/numpy/ma/core.py 

Può essere qualcosa di semplice come

def __getitem__(self, indx): 
    """x.__getitem__(y) <==> x[y] 
    """ 
    # _data = ndarray.view(self, ndarray) # change to: 
    _data = ndarray.copy(self, ndarray) 
    dout = ndarray.__getitem__(_data, indx) 
    return dout 

Ma ho il sospetto che da nel momento in cui sviluppi e collaudi completamente una sottoclasse di questo tipo, potresti innamorarti dell'approccio no-copy predefinito. Mentre questo business view-v-copy morde molti nuovi arrivati ​​(specialmente se provengono da MATLAB), non ho visto lamentele da parte di utenti esperti. Guarda altre domande SO assordanti; non vedrai molte chiamate copy().

Anche gli utenti regolari di Python si chiedono se un riferimento o una sezione è una copia o meno e se qualcosa è mutabile o meno.

ad esempio con le liste:

In [754]: ll=[1,2,[3,4,5],6] 
In [755]: llslice=ll[1:-1] 
In [756]: llslice[1][1:2]=[10,11,12] 
In [757]: ll 
Out[757]: [1, 2, [3, 10, 11, 12, 5], 6] 

modificando una voce di un elemento all'interno di una fetta modifica quello stesso elemento nella lista originale. A differenza di numpy, una sezione elenco è una copia. Ma è una copia superficiale. Devi fare uno sforzo extra per fare una copia profonda (import copy).

/usr/lib/python3/dist-packages/numpy/lib/index_tricks.py contiene alcune funzioni di indicizzazione per rendere più convenienti determinate operazioni di indicizzazione. Diverse sono in realtà classi o istanze di classe con i metodi personalizzati __getitem__. Possono anche fungere da modelli per personalizzare il taglio e l'indicizzazione.

Problemi correlati