2015-02-23 25 views
6

Tôi đang sử dụng trăn 3.4.1.
Đối với một danh sách duy nhất a=[1,2], nếu tôi tạo một bản sao của nó, b = a.copy() khi tôi thay đổi các mục trong b, nó sẽ không thay đổi các mục trong a.
Tuy nhiên, khi tôi xác định danh sách các danh sách (thực ra là ma trận) a = [[1,2],[3,4]], khi tôi gán b = a.copy(). Những gì tôi làm để liệt kê b thực sự ảnh hưởng đến a.
Tôi đã kiểm tra địa chỉ của họ, chúng khác nhau.
Có ai cho tôi biết tại sao không?Python sao chép danh sách các danh sách

ps: Những gì tôi đã làm là b[0][0] = x và mục trong một cũng đã được thay đổi.

+0

thể trùng lặp của [Làm thế nào để sao chép hoặc sao chép một danh sách bằng Python? ] (http://stackoverflow.com/questions/2612802/how-to-clone-or-copy-a-list-in-python) – aruisdante

Trả lời

5

Từ các tài liệu cho copy mô-đun:

Sự khác biệt giữa nông và sao chép sâu chỉ có liên quan cho các đối tượng hợp chất (đối tượng có chứa các đối tượng khác, như danh sách hoặc trường lớp):

  • Một bản sao nông xây dựng một đối tượng hợp chất mới và sau đó (trong phạm vi có thể) chèn tham chiếu vào nó vào các đối tượng được tìm thấy trong bản gốc.
  • Một bản sao sâu xây dựng một đối tượng hợp chất mới và sau đó, đệ quy, chèn các bản sao vào nó của các đối tượng được tìm thấy trong bản gốc.

Khi bạn gọi thường xuyên copy.copy() bạn đang thực hiện một nông bản sao. Điều này có nghĩa rằng trong trường hợp danh sách các danh sách, bạn sẽ nhận được một bản sao mới của danh sách bên ngoài, nhưng nó sẽ chứa các danh sách bên trong ban đầu làm các phần tử của nó. Thay vào đó, bạn nên sử dụng copy.deepcopy(), thao tác này sẽ tạo một bản sao mới của cả danh sách bên ngoài và bên trong.

Lý do bạn không nhận thấy điều này với ví dụ đầu tiên của bạn về việc sử dụng copy([1,2]) là nguyên thủy như int là không thay đổi và do đó không thể thay đổi giá trị của chúng mà không tạo một phiên bản mới. Nếu nội dung của danh sách thay vào đó là các đối tượng có thể thay đổi (như danh sách hoặc bất kỳ đối tượng nào do người dùng xác định có thành viên có thể thay đổi) thì bất kỳ đột biến nào của các đối tượng đó sẽ được thấy trong cả hai bản sao của danh sách.

+0

Cảm ơn bạn!Và một câu hỏi nữa về bản sao. Tôi có thể lấy một bản sao của một lớp học không? Giống như lớp cây, tôi có thể lấy một bản sao của một số đối tượng cây t1 bằng cách đơn giản không? – jack

+0

Có, bạn có thể sử dụng mô-đun 'copy' trên bất kỳ đối tượng nào xác định phương thức' __copy__' và '__deepcopy__'. Xem tài liệu được liên kết trong câu trả lời gốc để biết chi tiết cụ thể. Không có, thật đáng buồn, một hoạt động sao chép 'được xác định trước' trong Python giống như có các ngôn ngữ như C++ (thường là một điều tốt, bởi vì bản sao tạo tự động tạo của C++ thường sai đối với bất kỳ lớp không tầm thường nào). – aruisdante

+0

@jack Bạn có thể kiểm tra những gì đang diễn ra khi bạn sử dụng phương pháp sao chép trên [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 & chế độ = display & origin = opt-frontend.js & cumulative = false & heapPrimitives = false & textReferences = false & py = 3 & rawInputLstJSON =% 5B% 5D & curInstr = 0). Bạn có thể thấy tất cả các con trỏ được hiển thị ở đó. –

2

Có lẽ một danh sách hiểu như vậy:

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

... mặc dù nếu ma trận của bạn sâu hơn một lớp, danh sách hiểu có lẽ là ít thanh lịch hơn là chỉ sử dụng deepcopy.

chỉnh sửa - bản sao nông, như đã nêu, sẽ vẫn chứa tham chiếu đến các đối tượng bên trong danh sách. Vì vậy, ví dụ ...

>>> 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

Nó cũng ít rõ ràng hơn đối với người đọc bình thường những gì nó đang làm hơn là sử dụng các phương pháp từ 'copy', mặc dù nó có hiệu suất cao hơn một chút. – aruisdante

+0

Chắc chắn, có điều đó. Nhưng sự hiểu biết về danh sách hầu hết là pythonic, vì vậy tôi đoán nó phụ thuộc vào những gì được coi là 'rõ ràng', và cho ai. Trong mọi trường hợp, nếu ma trận quá lồng nhau thì đề xuất của tôi sẽ không hữu ích lắm, nhưng đối với một chiều, tôi không nghĩ nó quá tệ –

-3

Nó rất đơn giản, chỉ cần làm điều đó:

b = a 

dụ:

>>> a = [1, 2, 3] 
>>> b = a 
>>> b.append(4) 
>>> b 
[1, 2, 3, 4] 
>>> a 
[1, 2, 3, 4] 
Các vấn đề liên quan