2012-09-14 23 views
5

Các tài liệu của Python 3.2 's weakref mô-đun của WeakKeyDictionaryWeakValueDictionary có một ghi chú trên iterating trên các container:an toàn iterating trên WeakKeyDictionary và WeakValueDictionary

Lưu ý: Chú ý: Vì một WeakKeyDictionary được xây dựng trên đầu của một từ điển Python, nó không được thay đổi kích thước khi lặp qua nó. Điều này có thể khó đảm bảo cho một WeakKeyDictionary vì các hành động được thực hiện bởi chương trình trong quá trình lặp lại có thể làm cho các mục trong từ điển biến mất "bằng phép thuật" (như là một tác dụng phụ của việc thu gom rác).

Điều đó có vẻ khá nghiêm trọng như một đặc điểm kỹ thuật của hành vi của vùng chứa này. Đặc biệt là khi chạy mã sử dụng bộ gom rác của CPython (khi sử dụng cấu trúc dữ liệu chứa chu trình) hoặc sử dụng một triển khai Python khác (ví dụ: Jython), thì có vẻ như không có cách nào an toàn để lặp lại các bộ sưu tập này.

Làm cách nào để tôi có thể lặp lại an toàn các bộ sưu tập này khi bộ thu gom rác có thể xóa tham chiếu tại bất kỳ thời điểm nào trong chương trình của tôi? Có một giải pháp cho CPython là ưu tiên của tôi nhưng tôi cũng quan tâm đến vấn đề về các triển khai khác.

Đây có phải là cách an toàn để lặp qua WeakKeyDictionary không?

import weakref 

d = weakref.WeakKeyDictionary() 

... 

for k, v in list(d.items()): 
    ... 

Trả lời

6

Để an toàn, bạn phải giữ tham chiếu ở đâu đó. Sử dụng thành ngữ:

for k,v in list(d.items()): 

không hoàn toàn an toàn vì, mặc dù nó sẽ hoạt động hầu hết thời gian, trong lần lặp cuối vòng lặp danh sách có thể bị thu gom rác.

Cách đúng sẽ là:

items = list(d.items()) 
for k,v in items: 
    #do stuff that doesn't have a chance of destroying "items" 
del items 

Nếu bạn sử dụng một WeakKeyDictionary bạn chỉ có thể lưu trữ các phím, và các giá trị lưu trữ nếu bạn sử dụng WeakValueDictionary.

Trên ghi chú bên: trong python2 .items() đã trả về một danh sách.

Cuối cùng, điều đó phụ thuộc vào ý bạn là "an toàn". Nếu bạn chỉ đơn giản có nghĩa là lặp đi lặp lại sẽ tiến hành một cách chính xác (lặp lại một lần trên tất cả các yếu tố), sau đó:

for k,v in list(d.items()): 

là an toàn, bởi vì lặp qua từ điển được thực hiện bởi list(d.items()), sau đó bạn chỉ được lặp lại qua danh sách.

Nếu bạn, thay vào đó, có nghĩa là trong phần tử lặp không được "biến mất" khỏi từ điển dưới dạng tác dụng phụ của vòng for, thì bạn phải giữ tham chiếu mạnh cho đến cuối vòng lặp và yêu cầu này bạn lưu trữ danh sách trong một biến trước khi bắt đầu vòng lặp.

+2

Tại sao ví dụ đầu tiên của bạn không an toàn? Danh sách sẽ chứa các tham chiếu mạnh mẽ cho mỗi khóa và giá trị và trong lần lặp cuối cùng, 'k' và' v' giữ tham chiếu mạnh đến các đối tượng mà tôi quan tâm. Vì vậy, danh sách có thể là rác được thu thập ngay cả trước khi kết thúc lần cuối. Có đúng không? – Feuermurmel

+0

Điều đó giống như nói rằng 'cho k, v trong d.items()' là an toàn, bởi vì 'k' và' v' giữ tham chiếu mạnh mẽ với các đối tượng.Lặp lại là không an toàn nếu, bên trong for-loop, có một cơ hội cho 'k' và' v' bị xóa. Đối với các tác vụ đơn giản đủ lặp qua 'WeakKeyDictionary' nên an toàn. – Bakuriu

+3

Tôi có thể hiểu nhầm một cái gì đó, nhưng làm thế nào các đối tượng 'k' và' v' tham chiếu có thể bị xóa? Miễn là các biến này nằm trong phạm vi và không được ghi đè, các đối tượng được tham chiếu sẽ an toàn. Hay bạn đang nói về việc loại bỏ tất cả các tham chiếu mạnh mẽ đến các đối tượng đó trong lần lặp cuối cùng? Điều đó sẽ thay đổi từ điển nhưng sẽ không an toàn vì từ điển không được truy cập sau khi bắt đầu lặp lại. Bạn có thể đưa ra một ví dụ về những gì có thể sai trong lần lặp lại cuối cùng không? – Feuermurmel

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