Tôi tin rằng cách đơn giản nhất để có được những gì đang xảy ra là sử dụng một hình ảnh đại diện (ý tưởng của đại diện này không phải của tôi, mặc dù tôi thích nó).
Trước hết bạn phải hiểu rằng trong python chỉ có tài liệu tham chiếu cho đối tượng. Các đối tượng tự sống riêng rẽ với nhau. Ví dụ: danh sách [0, 1]
là một đối tượng danh sách chứa tham chiếu đối tượng 0
và đối tượng 1
. Tham chiếu là một loại liên kết . Điều này khác với các biến trong các ngôn ngữ khác, vì các biến thường là các vị trí bộ nhớ nơi bạn đặt mọi thứ. Trong python một "biến", tức là một định danh, chỉ đơn giản là một "tên" (= tham chiếu) cho một đối tượng.
Để hiểu điều này, hãy hình dung mối quan hệ giữa các đối tượng bằng phép ẩn dụ: Giả sử đối tượng là đá nặng trên biển, được liên kết với nhau bằng dây thừng và móc (¿). Trên bề mặt của biển sống các định danh đề cập đến các đối tượng. Các định danh là phao ngăn chặn các đối tượng chìm trong sâu (nơi họ nói, quái vật biển (hay còn gọi là Garbage Collector) sẽ phá hủy chúng).
Ví dụ, chúng ta có thể đại diện cho tình trạng này:
a = [0, 1]
Với sơ đồ sau đây:
___
( )
~~~~~~~~(a)~~~~~~~~
(___)
o ¿ o
| O
| o
|
|
+------+-------+
| [ ¿ , ¿ ] |
+----|-----|---+
| |
| |
o | |
O | |
| |
+-+-+ +-+-+
| 0 | | 1 |
+---+ +---+
o O o
)
() o
))() ((
(()(( ())
Như bạn có thể thấy các định danh a
đề cập, tức là được liên kết với một sợi dây thừng, vào đối tượng danh sách. Đối tượng danh sách có hai vị trí, mỗi vị trí chứa liên kết được kết nối với các đối tượng 0
và 1
.
Bây giờ, nếu chúng ta đã làm:
b = a
Từ định danh b
sẽ tham khảo cùng đối tượng của a
:
___ ___
( ) ( )
~~~~~~~~~~~(a)~~~~~~~~~~~~~~~(b)~~~~~~~~~~~~~~~~
(___) (___)
¿ ¿
\ /
o \ / o
o \ / o
-------+-------
O | [ ¿ , ¿ ] | O
----|-----|----
| |
+-+-+ +-+-+
o | 0 | | 1 |
+---+ +---+ o
O
o O
o
)
) ( ) (
(( )( (( )
()) () ( ()) ()
Khi bạn, thay vào đó, làm một bản sao cạn của a
, qua:
b = a[:]
Một danh sách mới được tạo ra, và các yếu tố của nó là bản của tài liệu tham khảo để các đối tượng được gọi bằng a
, tức là bạn đã thực hiện các bản sao của dây thừng, nhưng họ trỏ đến các yếu tố giống nhau:
___ ___
( ) ( )
~~~~~~~~~~~(a)~~~~~~~~~~~~~~~(b)~~~~~~~~~~~~~~~~
(___) (___)
O ¿ ¿ o
| |
o | |
| |
-------+------ ------+-------
| [ ¿ , ¿ ] | | [ ¿ , ¿ ] |
----|----|---- ----|----|----
| | | |
\ \ //
\ \ //
\ \ // o
o \ \ // o
\ \ // o
o \ \ //
\ \// o
O \ X /
\/\/
\/ \/
| |
| |
| |
+-+-+ +-+-+
| 0 | | 1 |
+---+ +---+
)
( ( ) (
)( ) ) ) (( ) ) )
() () ( ( ( ()) () ( ( (
Vì các số nguyên không thay đổi, không có sự khác biệt giữa việc sử dụng bản sao hoặc cùng một đối tượng giống nhau, nhưng khi bạn thay thế số nguyên bằng list
s, là có thể thay đổi, bạn sẽ sửa đổi các tham chiếu đến cùng một đối tượng. hành vi bạn thấy.
Nhìn bề ngoài, mã:
a = [[0, 1], [0, 1]]
b = a[:]
Kết quả trong:
___ ___
( ) ( )
~~~~~~~~~~~(a)~~~~~~~~~~~~~~~(b)~~~~~~~~~~~~~~~~
(___) (___)
O ¿ ¿ o
| |
o | |
| |
-------+------ ------+-------
| [ ¿ , ¿ ] | | [ ¿ , ¿ ] |
----|----|---- ----|----|----
| \ / |
| \ / |
| \ / |
| \ / |
| \ / |
| \ / |
| \/ |
| X |
| /\ |
| / \ |
| / \ |
| / \ |
| / \ |
| / \ |
| | \ |
| | | |
+----+-----+----+ +-----+----+----+
| [ ¿ , ¿ ] | | [ ¿ , ¿ ] |
+----|-----|----+ +----|-----|----+
\ \ / /
\ \ / /
\ \ / /
\ \ / /
\ \ / /
\ |/ /
| |/ /
| X /
| /| /
|/|/
\/ \/
Y Y
| |
+-+-+ +-+-+
| 0 | | 1 |
+---+ +---+
)
( ( ) (
)( ) ) ) (( ) ) )
() () ( ( ( ()) () ( ( (
Lưu ý cách danh sách b
đề cập đến các danh sách con cùng a
. (chi tiết triển khai: Trình biên dịch bytecode của CPython sẽ tối ưu hóa các biểu thức bằng chữ, để cùng một đối tượng 0
và 1
được sử dụng trong cả hai danh sách con. không có tất cả các yếu tố chung).
Bản sao sâu là bản sao tránh chia sẻ các đối tượng giống hệt nhau này.
Ví dụ, sau khi thực hiện:
import copy
a = [[0, 1], [0, 1]]
b = copy.deepcopy(a)
Tình hình là:
___ ___
( ) ( )
~~~~~~~~~~~(a)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(b)~~~~~~~~~~~~~~~~
(___) (___)
O ¿ ¿ o
| |
o | |
| |
-------+------ -------+------
| [ ¿ , ¿ ] | | [ ¿ , ¿ ] |
----|----|---- ----|----|----
| \ | \
| \ | \
| \ | \
| \ | \
| \ | \
| \ | \
| \ | \
| \ | \
| \ | \
| \ | \
| \ | \
| \ | \
+----+----------+ +--+------------+ +----+----------+ +--+------------+
| [ ¿ , ¿ ] | | [ ¿ , ¿ ] | | [ ¿ , ¿ ] | | [ ¿ , ¿ ] |
+----|-----|----+ +----|-----|----+ +----|-----|----+ +----|-----|----+
\ \ / / \ \ / /
\ \ / / \ \ / /
\ \ / / \ \ / /
\ \ / / \ \ / /
\ \ / / \ \ / /
\ |/ / \ |/ /
| |/ / | |/ /
| X / | X /
| /| / | /| /
|/|/ |/|/
\/ \/ \/ \/
Y Y Y Y
| | | |
+-+-+ +-+-+ +-+-+ +-+-+
| 0 | | 1 | | 0 | | 1 |
+---+ +---+ +---+ +---+
) )
( ( ) ( ( ( ) (
)( ) ) ) (( ) ) ) )( ) ) ) (( ) ) )
() () ( ( ( ()) () ( ( ( () () ( ( ( ()) () ( ( (
(Trên thực tế, nó có vẻ như copy.deepcopy
là đủ thông minh để tránh sao chép built-in các đối tượng là không thay đổi, chẳng hạn dưới dạng int
, long
, tuple
s đối tượng không thay đổi, v.v. vì vậy tất cả các danh sách con chia sẻ cùng một 0
và 1
đối tượng)
Lưu ý rằng các biểu đồ này cũng có thể giúp bạn hiểu cách tính toán tham chiếu hoạt động. Mỗi sợi dây là một tham chiếu, và cho đến khi một đối tượng có một chuỗi các tham chiếu đi đến phao (tức là một mã định danh) nó vẫn còn sống. Khi không có nhiều sợi dây để liên kết một vật thể với phao của bề mặt, thì các vật thể chìm xuống và bị phá hủy bởi bộ thu gom rác.
liên quan: http://stackoverflow.com/questions/3119901/python-deepcopylist-vs-new-list-old-list –