2015-04-21 13 views
5

Jestem początkujący w python i nie chcę ci tablice skopiować siebie, ale są one automatycznie:Python tablice są automatycznie kopiuje siebie

a = numpy.zeros(4) 
b = a 
a[1] = 10 
print b[1] 

i zwraca 10 zamiast 0. Jak zrobić Rozłączam te dwie tablice?

+4

Przypisanie nie tworzy kopii Aby zrozumieć, dlaczego twoje oczekiwania były błędne zobacz [Fakty i mity o nazwach i wartościach Pythona] (http://nedbatchelder.com/text/names.html) autorstwa Neda Batcheldera. leczenie tego, jeśli naprawdę zrozumiesz Python. –

Odpowiedz

2

Musisz kopię:

b = a.copy() 

b = a tworzy odniesienie tak a is b, są one zarówno wskazując w tej samej lokalizacji w pamięci, a.copy() faktycznie tworzy nowy obiekt.

In [5]: a = numpy.zeros(4)  
In [6]: b = a # reference 
In [7]: id(a) 
Out[7]: 140335847505968  
In [8]: id(b)   # same id's 
Out[8]: 140335847505968  
In [9]: a is b 
Out[9]: True  
In [10]: b = a.copy() # new object  
In [11]: id(a) 
Out[11]: 140335847505968  
In [12]: id(b) # # now different id's 
Out[12]: 140335437696176  
In [13]: a is b # b is no longer pointing to the same memory location 
Out[13]: False 

Jeśli plaster tablicę używając basic slicing, identyfikator będzie się różnić, ale wszelkie zmiany będą widoczne zarówno A i B, przy użyciu podstawowych indeksowanie Wszystkie tablice wygenerowane przez podstawową krojenia zawsze są widoki na oryginalnej tablicy. A view to Tablica, która nie jest właścicielem danych, ale odnosi się do danych innej macierzy. Widok jest nowym obiektem, ale zawartość nadal należy do oryginalnej tablicy.

Jednak stosując advanced indexingzaawansowane indeksowanie zawsze zwraca kopię danych

In [141]: a = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 
In [142]: b = a[1:7:2] # basic indexing/view 
In [143]: id(a) 
Out[143]: 140335437385856  
In [144]: id(b)  
Out[144]: 140335437356528  
In [145]: b[0] = 999  
In [146]: a 
Out[146]: array([ 0, 999, 2, 3, 4, 5, 6, 7, 8, 9]) 
In [148]: b 
Out[148]: array([999, 3, 5])  
In [149]: a = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])  
In [150]: b = a[[0,3,5]] # advanced indexing/copy 
In [151]: b 
Out[151]: array([0, 3, 5])  
In [152]: b[0] = 999  
In [153]: a 
Out[153]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])  
In [154]: b 
Out[154]: array([999, 3, 5]) 
In [157]: a = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 
In [158]: b = a[a] # copy 
In [159]: b 
Out[159]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])  
In [160]: b[0] = 99  
In [161]: a 
Out[161]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])  
In [162]: b 
Out[162]: array([99, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 

ten jest specyficzny numpy zachowanie, krojenie listę płaską regularne Python zawsze utworzyć nową listę, gdzie zmiany w nie będzie odzwierciedlone w b.

In [190]: a = [1,2,3,4,5] 

In [191]: b = a[:3] 

In [192]: b[0] = 999 

In [193]: a 
Out[193]: [1, 2, 3, 4, 5] 

In [194]: b 
Out[194]: [999, 2, 3] 

Gdzie będziesz złapany z listy Python jest jeśli lista zawiera listy zagnieżdżone i utworzyć płytkie kopię:

In [197]: a = [[1,2,3],[4,5]] 
In [198]: b = a[:]  
In [199]: id(a) 
Out[199]: 140335437468296  
In [200]: id(b) 
Out[200]: 140335437417992 
In [201]: b[0][0] = 999 
In [202]: b 
Out[202]: [[999, 2, 3], [4, 5]] 
In [203]: a 
Out[203]: [[999, 2, 3], [4, 5]] 

trzeba byłoby dokonać copy.deepcopy:

In [204]: a = [[1,2,3],[4,5]]  
In [205]: from copy import deepcopy 
In [206]: b = deepcopy(a)  
In [207]: b[0][0] = 999  
In [208]: b 
Out[208]: [[999, 2, 3], [4, 5]]  
In [209]: a 
Out[209]: [[1, 2, 3], [4, 5]] 
+0

Należy zauważyć d, że 'a.copy()' jest nieprawidłowe Python 2, z którego korzysta OP. – erb

+3

@erb, działa również w python2, OP ma tablicę numpy, a nie listę. –

+1

Przepraszam, masz rację, tęskniłeś. – erb

-1

Pamiętaj, że listy w Pythonie są zmienne, co oznacza, że ​​podczas wykonywania operacji przypisania nie tworzy się jej kopia, ale kopiuje odniesienie. Co oznacza, że ​​obie zmienne są tą samą listą.

Można to zrobić na przykład:

b = a[::] który tworzy kopię oryginalnej listy.

W każdym razie, polecam przeczytanie sekcji list Python.org po więcej informacji.

+3

Przypisanie działa w ten sam sposób, niezależnie od tego, czy przypisana wartość jest niezmienny. Zgadzam się z tą odpowiedzią, ponieważ dodaje ona niepotrzebnego zamieszania do tego, co powinno być prostszym wyjaśnieniem. Również 'b = a [::]' jest częściej pisane 'b = a [:]'. –

+3

Kopiowanie plasterka nie działa z numpy tablicami. – Shashank

-1

można użyć modułu kopiowania jak ten

from copy import copy 
a = numpy.zeros(4) 
b = copy(a) 
a[1] = 10 
print b[1] 

ma to związek z faktem, że kiedy robisz b = a przypisać odniesienie a do b.

Więcej na ten temat można znaleźć w tej odpowiedzi: How to clone or copy a list?

+3

To jest dobra ogólna wiedza na temat kopiowania, ale w konkretnym przypadku tablic numpy można liczyć na tablicę mającą metodę "copy". –

4

„Macierze są automatycznie kopiuje siebie” jest fałszywe oświadczenie z kilku powodów.Głównym powodem jest to, że masz tylko jedną tablicę i dwie nazwy zmiennych, które odnoszą się do tej tablicy.

Oto trzy sposoby, aby skopiować numpy array (tj utworzyć kolejną tablicę dokładnie podobnego).

>>> a = numpy.zeros(4) 
>>> b = a.copy() 
>>> c = numpy.copy(a) 
>>> d = numpy.array(a) 
>>> a[1] = 10 
>>> a 
array([ 0., 10., 0., 0.]) 
>>> b 
array([ 0., 0., 0., 0.]) 
>>> c 
array([ 0., 0., 0., 0.]) 
>>> d 
array([ 0., 0., 0., 0.]) 

pamiętać, że plaster-kopiowanie (np e = a[:]) będzie nie praca z NumPy tablic

+0

"tworzy kolejną tablicę, która jest głęboką kopią pierwszego" jest nieco myląca: to, co robi operacja plastra, tworzy kolejną tablicę (np. Nowy obiekt Pythona typu "numpy.ndarray"), który * dzieli * to samo blok danych jako oryginalna tablica. Nie ma kopiowania danych * tablicowych *, głębokich lub innych. –

+0

@MarkDickinson Jest to jednak kopia głęboka. Wypróbuj 'a = numpy.zeros (4), b = a [:]; a [0] to b [0]', a zobaczysz, że daje to Fałsz, byłem również zaskoczony tym zachowaniem. Z pewnością różni się od list. Jednakże, nawet jeśli jest to głęboka kopia w Pythonie, masz zasadniczo dwa różne obiekty, które wskazują na ten sam adres w pamięci. W przypisaniu wartość w tym adresie jest modyfikowana, dlatego widzisz zmianę między obiektami. – Shashank

+2

Dzieje się tak dlatego, że gdy wyciągniesz 'a [0]' lub 'b [0]', skutecznie zbijasz unboxed wartość przechowywaną w tablicy i tworząc nowy obiekt Pythona w tym momencie. Spróbuj 'a [0] to [0]', a zobaczysz także 'False'. Następnie spróbuj zmodyfikować 'a': zobaczysz, że zawartość' b' również się zmienia (i na odwrót). –

Powiązane problemy