2013-08-20 70 views
2

我在Python中遇到了一個非常奇怪的行爲。 使用從UserDict派生的類,迭代器a.items()表現不同在for循環中比a.data.items(),即使兩者是相同相同的迭代器對象在for循環中產生不同的結果?

Python 3.3.1 (default, Apr 17 2013, 22:32:14) 
[GCC 4.7.3] on linux 
Type "help", "copyright", "credits" or "license" for more information. 
>>> from datastruct import QueueDict 
>>> a=QueueDict(maxsize=1700) 
>>> for i in range(1000): 
...  a[str(i)]=1/(i+1) 
... 
>>> a.items() 
ItemsView(OrderedDict([('991', 0.0010080645161290322), ('992', 0.0010070493454179255), ('993', 0.001006036217303823), ('994', 0.0010050251256281408), ('995', 0.001004016064257028), ('996', 0.0010030090270812437), ('997', 0.001002004008016032), ('998', 0.001001001001001001), ('999', 0.001)])) 
>>> a.data.items() 
ItemsView(OrderedDict([('991', 0.0010080645161290322), ('992', 0.0010070493454179255), ('993', 0.001006036217303823), ('994', 0.0010050251256281408), ('995', 0.001004016064257028), ('996', 0.0010030090270812437), ('997', 0.001002004008016032), ('998', 0.001001001001001001), ('999', 0.001)])) 
>>> a.items()==a.data.items() 
True 
>>> # nevertheless: 
... 
>>> for item in a.items(): print(item) 
... 
('992', 0.0010070493454179255) 
>>> for item in a.data.items(): print(item) 
... 
('993', 0.001006036217303823) 
('994', 0.0010050251256281408) 
('995', 0.001004016064257028) 
('996', 0.0010030090270812437) 
('997', 0.001002004008016032) 
('998', 0.001001001001001001) 
('999', 0.001) 
('991', 0.0010080645161290322) 
('992', 0.0010070493454179255) 
>>> 

類定義如下:

import collections, sys 

class QueueDict(collections.UserDict): 

    def __init__(self, maxsize=1*((2**10)**2), *args, **kwargs): 
     self._maxsize=maxsize 
     super().__init__(*args, **kwargs) 
     self.data=collections.OrderedDict(self.data) 

    def __getitem__(self, key): 
     self.data.move_to_end(key) 
     return super().__getitem__(key) 

    def __setitem__(self, key, value): 
     super().__setitem__(key, value) 
     self._purge() 

    def _purge(self): 
     while sys.getsizeof(self.data) > self._maxsize: 
      self.data.popitem(last=False) 

這很令人不安。任何想法(通過「視覺」檢查,也可以通過(a.items()==a.data.items()) == True],同一個對象如何以及爲什麼會在for循環中表現不同?

感謝您的幫助和意見!

+0

你在這裏看到的是什麼區別? –

+0

在for循環中使用兩個對象之間究竟有什麼區別? – NPE

+0

@DanielRoseman:第一個元素迭代第一個,第二個迭代! –

回答

2

迭代時更改集合可能會產生一些意想不到的後果(在這種情況下)。

Your getter;

def __getitem__(self, key): 
    self.data.move_to_end(key) 
    return super().__getitem__(key) 

...移動當前關鍵集合的末尾,這將使用於遍歷a.items停止,因爲它認爲它達到了集合的末尾。

評論move_to_end行允許迭代按預期運行。

當你迭代a.data.items時,你的getter永遠不會被調用,所以它沒有問題。

+0

謝謝你非常有見地的答案!但是:在覆蓋類中的__items__方法後:'def __items __(self):return self.data.items()',我仍然得到上述症狀(輸出) 。據我的理解,在這種情況下'QueueDict' getter既不被調用,也不被叫做QueueDict.data,它是OrderedDict。有任何想法嗎? –

+1

@ASz'__items __()'中的斷點似乎永遠不會被擊中,我無法找到關於該內部函數的文檔,是否指'__iter __()'? –

+0

哦,該死的,這是我必須重寫的簡單的'items()'方法。我在我的思維導圖中用'__iter __()'混合了'items()'。重寫'def items(self):return self.data.items()'for循環按預期工作!謝謝Joachim! –

相關問題