2010-02-16 64 views
9

Tôi có thể thiếu điều gì đó về hành vi dự định của danh sách mở rộng, nhưng tại sao những điều sau xảy ra?Mở rộng danh sách các danh sách bằng Python?

x = [[],[]] 
y = [[]] * 2 

print x  # [[],[]] 
print y  # [[],[]] 
print x == y # True 

x[0].extend([1]) 
y[0].extend([1]) 

print x # [[1],[]], which is what I'd expect 
print y # [[1],[1]], wtf? 

Tôi đoán nhà điều hành * đang làm điều gì đó bất ngờ ở đây, mặc dù tôi không chắc chắn chính xác điều gì. Nó có vẻ như một cái gì đó đang xảy ra dưới mui xe mà làm cho x và y ban đầu (trước khi gọi mở rộng) không thực sự được bình đẳng mặc dù các nhà điều hành ==repr cả hai sẽ làm cho nó có vẻ như là họ giống hệt nhau.

Tôi chỉ gặp vấn đề này vì tôi muốn điền trước một danh sách các danh sách trống có kích thước xác định trong thời gian chạy, và sau đó nhận ra rằng nó không hoạt động theo cách tôi tưởng tượng. Tôi có thể tìm thấy một cách tốt hơn để làm điều tương tự, nhưng bây giờ tôi tò mò là tại sao điều này không hiệu quả. Đây là Python 2.5.2 BTW - Tôi không có một phiên bản mới hơn được cài đặt vì vậy nếu đây là một lỗi tôi không chắc chắn nếu nó đã được cố định.

+0

Tôi biết những gì phụ thêm, tôi vừa mới đưa ra một ví dụ giả tạo vì lợi ích của câu hỏi. –

Trả lời

16

Trong trường hợp [something] * 2, python đơn giản là tạo bản sao tham chiếu. Do đó, nếu (các) loại được kèm theo có thể thay đổi, việc thay đổi chúng sẽ được phản ánh ở bất kỳ nơi nào mục được tham chiếu.

Trong ví dụ của bạn, y[0]y[1] trỏ đến cùng một đối tượng danh sách được đính kèm. Bạn có thể xác minh điều này bằng cách thực hiện y[0] is y[1] hoặc luân phiên id(y[0]) == id(y[1]).

Tuy nhiên bạn có thể tái assign yếu tố danh sách, vì vậy nếu bạn đã thực hiện:

y[0] = [1] 

Bạn sẽ đã tái-bound phần tử đầu tiên vào một danh sách mới có chứa các yếu tố "1", và bạn sẽ đã có kết quả mong đợi của bạn.

Vùng chứa trong tham chiếu cửa hàng trăn và có thể trong hầu hết các vùng chứa chuỗi để tham chiếu cùng một mục nhiều lần. Một danh sách có thể thực sự tham chiếu chính nó như là một phần tử, mặc dù tính hữu ích của điều này bị hạn chế.

Vấn đề này sẽ không đã đưa ra nếu bạn đã nhân với một danh sách có chứa loại không thay đổi:

a = [0, 1] * 2 

Trên đây sẽ cung cấp cho bạn danh sách [0, 1, 0, 1] và thực sự cả hai trường hợp của 1 điểm đến cùng một đối tượng, nhưng vì chúng không thay đổi, bạn không thể thay đổi giá trị của đối tượng int chứa "1", chỉ gán lại các phần tử.

Vì vậy, thực hiện: a[1] = 5 sẽ dẫn đến a hiển thị là [0, 5, 0, 1].

+0

Cảm ơn, điều đó có ý nghĩa. –

4

Tuyên bố y = [[]] * 2 liên kết y vào danh sách chứa 2 bản sao của cùng một danh sách. Sử dụng:

y = [[], []] 

hoặc

y = [[] for n in range(2)] 
+4

Về mặt kỹ thuật, đó là hai tham chiếu đến cùng một danh sách chứ không phải bản sao. – Crast

+0

u có nghĩa là "2 tham chiếu" thay vì "2 bản sao", phải không?tôi đề nghị rằng như là một chỉnh sửa – kmonsoor

1

y chứa hai tham chiếu đến một duy nhất, có thể thay đổi, danh sách.

Các vấn đề liên quan