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 a
odnosi, 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.
pokrewne: http://stackoverflow.com/questions/3119901/python-deepcopylist-vs-new-list-old-list –