2013-07-05 18 views
18

Mam nadzieję, że ktoś mi w tym pomoże.Python: kopiowanie listy na liście

Jestem nowicjuszem w Pythonie i próbuję ustalić, co robię źle.

Już przeszukaliśmy i dowiedzieliśmy się, że zmienne Pythona można powiązać, tak że zmiana jednej zmienia drugą, a ja wykonałem wiele testów z funkcją id(), aby poradzić sobie z tą koncepcją. Ale wydaje mi się, że znalazłem wyjątek Mam nadzieję, że ktoś może wyjaśnić ...

Po pierwsze, następujące prace zgodnie z oczekiwaniami wykonają niezależną kopię listy.

>>> a = [0,0] 
>>> b = a[:] 
>>> print a is b 
False 
>>> b[0]=1 
>>> print a 
[0,0] 
>>> print b 
[1,0] 

Ale jeśli zmienię to nieco tak, że a jest lista w liście, że zmiany ...

>>> a = [[0,0],[0,0]] 
>>> b = a[:] 
>>> print a is b 
False 
>>> b[0][0]=1 
>>> print a 
[[1, 0], [0, 0]] 
>>> print b 
[[1, 0], [0, 0]] 

Teraz widzimy, że każda aktualizacja b stosuje się również do a, ale jeszcze wynik print a is b zwraca False ?? Sprawdziłem to również przed id(), wszystko mówi, że są one niezależne od siebie, ale kiedy aktualizuję to samo odnosi się do innych?

Czy ktoś może to wyjaśnić?

Zauważam, że mam te z http://labs.codecademy.com/#:workspace, więc moja pierwsza myśl jest taka, że ​​to tylko błąd na ich stronie, ale nie wiem?

EDIT:

Dziękuję wszystkim za wielkie odpowiedzi tak daleko. To było szybkie! Wiem, że to było prawdopodobnie wcześniej zadawane, ale było to trudne do wyszukania.

Ponieważ wszystkie odpowiedzi są poprawne, zaczekam dzień przed oznaczeniem. kto ma najwięcej +1 dostanie znak :)

+2

pokrewne: http://stackoverflow.com/questions/3119901/python-deepcopylist-vs-new-list-old-list –

Odpowiedz

18

b = a[:] tworzy shallow copy z a, więc zmieniając zmienne wykazów w terminie b wciąż te same skutki list w a.

Innymi słowy, a i b nie wskazują na tej samej liście (dlatego a is not b), ale raczej dwa różne listy, które oboje zawierają te same dwie listy. Zmiana jednej z tych list następuje poprzez b[0][0] = 1 i ta zmiana pojawia się w a.

Wspomniałeś, że grały z id(), więc spojrzeć na to:

>>> a = [[0,0],[0,0]] 
>>> b = a[:] 
>>> id(a) 
2917280     # <----+ 
>>> id(b)     #  |----- different! 
2771584     # <----+ 
>>> id(a[0]), id(a[1]) 
(2917320, 2917360)   # <----+ 
>>> id(b[0]), id(b[1])  #  |----- same! 
(2917320, 2917360)   # <----+ 
13

Trzeba dokonać deepcopy listy. a[:] sprawia tylko kopii płytkiej - see docs

Można użyć copy.deepcopy funkcję:

>>> import copy 
>>> a = [[0,0],[0,0]] 
>>> b = copy.deepcopy(a) 
>>> b 
[[0, 0], [0, 0]] 
>>> b[0][0]=1 
>>> a 
[[0, 0], [0, 0]] 
4

a jest lista list.Gdy wykonasz b=a[:], utworzysz nową listę, ale skopiujesz elementy. Tak więc b jest inną listą, ale elementy (podlisty) są takie same.

3

W obu przypadkach tworzy się niezależną listę. Tak więc a is b jest zawsze fałszywe.

W pierwszym przypadku dodaje się inne wartości do jednej z list.

W drugim przypadku obie listy zawierają te same wartości.

Jest to jak gdyby piszesz

l = [] 
a = [l, l] 
b = [l, l] 

a is not b, a mimo to zawierają one te same dane.

Jeśli modyfikować l teraz, ta zmiana jest widoczna przez wszystkich a[0], a[1], b[0] i b[1].

3

Chociaż a is b zwraca False, a[0] is b[0] zwraca True. Więc po zmianie b[0] jesteś koniecznie zmieniając a[0]

>>> a = [[0,0],[0,0]] 
>>> b = a[:] 

>>> # a[0] is b[0] 
>>> print a[0] is b[0] 
True 

>>> a.append('more stuff') 
>>> print a 
[[0, 0], [0, 0], 'more stuff'] 
>>> print b 
[[0, 0], [0, 0]] 
6

Wierzę, najprostszym sposobem, aby dostać to, co się dzieje jest użycie reprezentację wizualną (idea tej reprezentacji nie jest moja, chociaż kocham go).

Przede wszystkim musisz zrozumieć, że w python są tylko odniesienia do obiektów. Obiekty same żyją osobno. Na przykład lista [0, 1] jest obiektem listy, który zawiera odwołania do obiektu 0 i obiektu 1. Odwołanie jest rodzajem łącza. Różni się to od zmiennych w innych językach, ponieważ zmiennymi są zazwyczaj lokalizacje pamięci, w których umieszczane są elementy. W pythonie "zmienna", tj. Identyfikator, jest po prostu "nazwą" (= odniesieniem) dla obiektu.

Aby to zrozumieć, zilustrujmy relacje między obiektami za pomocą metafory: Powiedzmy, że obiekty to ciężkie skały w morzu, połączone ze sobą za pomocą lin i haków (¿). Na powierzchni morza znajdują się identyfikatory, które odnoszą się do obiektów. Identyfikatory są bojami, które uniemożliwiają zatonięcie przedmiotów w głębinach (gdzie, jak mówią, potwory morskie (inaczej Garbage Collector) zniszczyłyby je).

Na przykład, możemy reprezentować tę sytuację:

a = [0, 1] 

z następującym schematem:

  ___ 
     ( ) 
~~~~~~~~(a)~~~~~~~~ 
     (___) 
o  ¿  o 
      |  O 
      | o 
      | 
      | 
    +------+-------+ 
    | [ ¿ , ¿ ] | 
    +----|-----|---+ 
     |  | 
     |  | 
    o |  | 
O  |  | 
     |  | 
     +-+-+ +-+-+ 
     | 0 | | 1 | 
     +---+ +---+ 

o     O o 
    ) 
    ()    o 
))()  ((
(()((  ()) 

Jak widać identyfikator aodnosi, czyli jest związana z liny, do obiektu listy. Obiekt listy ma dwa gniazda, z których każdy zawiera łącze połączone z obiektami 0 i 1.

Teraz, jeśli zrobiliśmy:

b = a 

Identyfikator b odsyła do tego samego obiektu z a:

  ___     ___ 
      ( )    ( ) 
~~~~~~~~~~~(a)~~~~~~~~~~~~~~~(b)~~~~~~~~~~~~~~~~ 
      (___)    (___) 
      ¿     ¿ 
       \    /
    o   \    /   o 
    o    \   /   o 
       -------+------- 
    O   | [ ¿ , ¿ ] |    O 
       ----|-----|---- 
        |  | 
        +-+-+ +-+-+ 
     o  | 0 | | 1 | 
        +---+ +---+    o 
    O 
     o        O 
             o 


       ) 
      ) (     ) (
     (( )(    (( ) 
     ()) () (   ()) () 

Gdy zamiast tego zrobić płytkie kopię z a, przez:

b = a[:] 

Nowa lista jest tworzona, a jego elementy są kopie z odniesień do przedmiotów określonych przez a, tzn wykonane kopie linach, ale wskazują one do tych samych elementów:

   ___     ___ 
       ( )    ( ) 
    ~~~~~~~~~~~(a)~~~~~~~~~~~~~~~(b)~~~~~~~~~~~~~~~~ 
       (___)    (___) 
    O   ¿     ¿    o 
       |     | 
     o   |     | 
       |     | 
      -------+------  ------+------- 
     | [ ¿ , ¿ ] |  | [ ¿ , ¿ ] | 
      ----|----|----  ----|----|---- 
       | |    | | 
       \ \   //
       \ \   //
       \ \  //   o 
    o    \ \  //   o 
        \ \ //    o 
     o   \ \ //
        \ \//   o 
    O     \ X /
         \/\/
         \/ \/ 
         |  | 
         |  | 
         |  | 
         +-+-+ +-+-+ 
         | 0 | | 1 | 
         +---+ +---+ 



       ) 
      ( (    )  (
    )( ) ) )   (( ) ) ) 
    () () ( ( (  ()) () ( ( (

Ponieważ liczby całkowite są niezmienne, nie ma żadnej różnicy między używaniem kopii lub tymi samymi identycznymi obiektami, ale po zamianie liczb całkowitych na list s, które są zmienne, kończy się modyfikowanie odniesień do tego samego obiektu, stąd zachowanie, które widzisz.

Wizualnie, kod:

a = [[0, 1], [0, 1]] 
b = a[:] 

Wyniki w:

   ___     ___ 
       ( )    ( ) 
    ~~~~~~~~~~~(a)~~~~~~~~~~~~~~~(b)~~~~~~~~~~~~~~~~ 
       (___)    (___) 
    O   ¿     ¿    o 
       |     | 
     o   |     | 
       |     | 
      -------+------  ------+------- 
     | [ ¿ , ¿ ] |  | [ ¿ , ¿ ] | 
      ----|----|----  ----|----|---- 
       |  \   / | 
       |  \   / | 
       |  \  /  | 
       |  \  /  | 
       |   \ /  | 
       |   \ /  | 
       |   \/   | 
       |   X   | 
       |   /\   | 
       |  / \   | 
       |  / \   | 
       |  /  \  | 
       |  /  \  | 
       | /   \  | 
       |  |    \  | 
       |  |    | | 
     +----+-----+----+ +-----+----+----+ 
     | [ ¿ , ¿ ] | | [ ¿ , ¿ ] | 
     +----|-----|----+ +----|-----|----+ 
       \  \   / /
       \  \  / /
       \  \  / /
        \  \ / /
        \  \ / /
        \  |/ /
        | |/ /
        | X /
        | /| /
        |/|/
        \/ \/
         Y  Y 
         |  | 
        +-+-+ +-+-+ 
        | 0 | | 1 | 
        +---+ +---+ 


       ) 
     ( (    )  (
    )( ) ) )   (( ) ) ) 
    () () ( ( (  ()) () ( ( (

nocie jak lista b odnosi się do tych samych podlist z a. (szczegóły implementacji: kompilator bajtów CPython zoptymalizuje wyrażenia dosłowne, tak aby te same obiekty 0 i 1 były używane w obu podlistach.Ale jest także pewne buforowanie dla małych liczb całkowitych, ale to nie jest ważne.W ogólnym przypadku podlisty nie mają wszystkich wspólnych elementów).

Głęboka kopia to kopia, która pozwala uniknąć tego samego podziału identycznych obiektów.

Na przykład, po wykonaniu:

import copy 
a = [[0, 1], [0, 1]] 
b = copy.deepcopy(a) 

Sytuacja jest:

   ___            ___ 
       ( )           ( ) 
    ~~~~~~~~~~~(a)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(b)~~~~~~~~~~~~~~~~ 
       (___)           (___) 
    O   ¿            ¿    o 
       |            | 
     o   |            | 
       |            | 
      -------+------         -------+------ 
     | [ ¿ , ¿ ] |         | [ ¿ , ¿ ] | 
      ----|----|----         ----|----|---- 
       |  \           |  \ 
       |  \           |  \ 
       |  \          |  \ 
       |  \          |  \ 
       |   \          |   \ 
       |   \          |   \ 
       |   \         |   \ 
       |   \         |   \ 
       |    \         |    \ 
       |    \         |    \ 
       |    \        |    \ 
       |    \        |    \ 
     +----+----------+ +--+------------+   +----+----------+ +--+------------+ 
     | [ ¿ , ¿ ] | | [ ¿ , ¿ ] |   | [ ¿ , ¿ ] | | [ ¿ , ¿ ] | 
     +----|-----|----+ +----|-----|----+   +----|-----|----+ +----|-----|----+ 
       \  \   / /      \  \   / /
       \  \  / /      \  \  / /
       \  \  / /       \  \  / /
        \  \ / /       \  \ / /
        \  \ / /        \  \ / /
        \  |/ /        \  |/ /
        | |/ /         | |/ /
        | X /         | X /
        | /| /         | /| /
        |/|/          |/|/
        \/ \/          \/ \/
         Y  Y           Y  Y 
         |  |           |  | 
        +-+-+ +-+-+          +-+-+ +-+-+ 
        | 0 | | 1 |          | 0 | | 1 | 
        +---+ +---+          +---+ +---+ 






       )            ) 
     ( (    )  (    ( (    )  (
    )( ) ) )   (( ) ) )  )( ) ) )   (( ) ) ) 
    () () ( ( (  ()) () ( ( ( () () ( ( (  ()) () ( ( (

(Faktycznie, wydaje się copy.deepcopy jest wystarczająco inteligentny, aby uniknąć kopiowania wbudowanych obiektów, które są niezmienne, takie jako int, long, tuple s niezmiennych obiektów itp. , więc wszystkie podlisty mają ten sam obiekt 0 i 1)


Należy pamiętać, że te diagramy mogą również pomóc w zrozumieniu działania licznika odwołań. Każda lina jest odniesieniem i dopóki obiekt nie ma łańcucha odniesień, który przechodzi do boi (tj. Identyfikatora), pozostaje on przy życiu. Kiedy nie ma już lin do połączenia obiektu z bojami na powierzchni, przedmioty znikają i zostają zniszczone przez śmieciarz.

+4

[Jeśli lubisz ASCII-Art] (http: // www .asciiflow.com/# Draw) –

0

Jest alternatywą dla kosztowne obliczeniowo deepcopy gdy masz do czynienia z listami w środku list

origvector=[] 
    for ind in range(0, len(testvector)): 
     origvector.append(testvector[ind][:]) 

W tym przykładzie „testvector” jest macierzą n wektorów, każdy element zawierający listę trzech artykuł . Tak:

{0,1,2}{10,20,30} 
{3,4,5}{40,50,60} 
{6,7,8}{70,80,90} 
Powiązane problemy