2015-02-23 14 views
6

Używam Pythona 3.4.1.
Dla pojedynczej listy a=[1,2], jeśli zrobię jej kopię, b = a.copy(), gdy zmienię pozycje w b, to nie zmieni pozycji w a.
Jednak, gdy zdefiniuję listę list (w rzeczywistości macierz) a = [[1,2],[3,4]], po przypisaniu b = a.copy(). To, co robię, aby wyświetlić listę b, dotyczy w rzeczywistości a.
Sprawdziłem ich adresy, są różne.
Czy ktoś może mi powiedzieć, dlaczego?Python skopiuj listę list

ps: To, co zrobiłem, to b[0][0] = x, a przedmiot w a także został zmieniony.

+0

możliwe duplikat [Jak sklonować lub skopiować listę w Pythonie? ] (http://stackoverflow.com/questions/2612802/how-to-clone-or-copy-a-list-in-python) – aruisdante

Odpowiedz

5

Od docs dla modułu copy:

Różnica między płytkich i głębokich kopiowania ma znaczenie tylko dla obiektów złożonych (obiekty, które zawierają inne obiekty, takie jak list lub instancji klas):

  • Płytka kopia tworzy nowy obiekt złożony, a następnie (w miarę możliwości) wstawia do niego odniesienia do obiektów znalezionych w oryginale.
  • Głęboka kopia tworzy nowy obiekt złożony, a następnie rekurencyjnie wstawia do niego kopie obiektów znalezionych w oryginale.

Po wywołaniu regularne copy.copy() wykonujesz płytkie kopię. Oznacza to, że w przypadku listy-list, otrzymasz nową kopię listy zewnętrznej, ale będzie ona zawierała oryginalne listy wewnętrzne jako jej elementy. Zamiast tego powinieneś użyć copy.deepcopy(), która utworzy nową kopię zarówno zewnętrznej, jak i wewnętrznej listy.

Powodem, dla którego nie zauważyłeś tego z pierwszym przykładem użycia copy([1,2]) jest to, że prymitywy takie jak int są niezmienne, a zatem nie można zmienić ich wartości bez tworzenia nowej instancji. Jeśli zamiast tego zawartość listy była zmiennymi obiektami (takimi jak listy lub dowolny obiekt zdefiniowany przez użytkownika z zmiennymi elementami), to każda mutacja tych obiektów byłaby widoczna w obu kopiach listy.

+0

Dziękujemy!I jeszcze jedno pytanie o kopię. Czy mogę dostać kopię klasy? Podobnie jak klasa drzewa, czy mogę uzyskać kopię jakiegoś obiektu drzewa t1 w prosty sposób? – jack

+0

Tak, możesz użyć modułu 'copy' na dowolnym obiekcie, który definiuje metody' __copy__' i '__deepcopy__'. Aby poznać szczegóły, zapoznaj się z połączoną dokumentacją w oryginalnej odpowiedzi. Niestety nie jest to "zdefiniowana" operacja kopiowania w Pythonie, tak jak w językach takich jak C++ (co zwykle jest dobre, ponieważ automatycznie generowany przez C++ konstruktor kopii jest często niepoprawny dla każdej nietrywialnej klasy). – aruisdante

+0

@jack Możesz sprawdzić, co się dzieje, gdy używasz metody kopiowania na [pythontutor.com] (http://www.pythontutor.com/visualize.html#code=a+%3D+%5B%5B1,+2% 5D, +% 5B3, + 4% 5D% 5D% 0Ab +% 3D + a.copy()% 0Ab% 5B0% 5D% 5B0% 5D +% 3D + 9 i tryb = wyświetlanie i pochodzenie = opt-frontend.js i zbiorcza = wartość false i heapPrimitives = false i textReferences = false & py = 3 & rawInputLstJSON =% 5B% 5D i curInstr = 0). Możesz zobaczyć wszystkie wizualizowane tam wskaźniki. –

2

Być może lista rozumienie jako takie:

new_list = [x[:] for x in old_list] 

... choć jeśli macierze są głębsze niż jedna warstwa, lista rozumienie jest prawdopodobnie mniej elegancki niż tylko za pomocą deepcopy.

edycja - płytka kopia, jak stwierdzono, nadal będzie zawierała odniesienia do obiektów na liście. Tak na przykład ...

>>> this = [1, 2] 
>>> that = [33, 44] 
>>> stuff = [this, that] 
>>> other = stuff[:] 
>>> other 
[[1, 2], [33, 44]] 
>>> other[0][0] = False 
>>> stuff 
[[False, 2], [33, 44]] #the same problem as before 
>>> this 
[False, 2]    #original list also changed 
>>> other = [x[:] for x in stuff] 
>>> other 
[[False, 2], [33, 44]] 
>>> other[0][0] = True 
>>> other 
[[True, 2], [33, 44]] 
>>> stuff 
[[False, 2], [33, 44]] #copied matrix is different 
>>> this 
[False, 2]    #original was unchanged by this assignment 
+1

Dla zwykłego czytelnika jest także o wiele mniej oczywiste, co robi, niż używanie metod z 'copy', choć jest nieco bardziej wydajne. – aruisdante

+0

Jasne, jest takie. Ale rozumienie list jest najbardziej pythonic, więc myślę, że to zależy od tego, co jest uważane za "jasne" i do kogo. W każdym razie, jeśli macierz jest zbyt zagnieżdżona, moja sugestia nie byłaby zbyt pomocna, ale dla jednego wymiaru nie uważam, że jest zbyt źle –

-3

To bardzo proste, wystarczy zrobić:

b = a 

Exemple:

>>> a = [1, 2, 3] 
>>> b = a 
>>> b.append(4) 
>>> b 
[1, 2, 3, 4] 
>>> a 
[1, 2, 3, 4]