2016-11-16 78 views
4
class Test(object): 

    def __init__(self, store): 
     assert isinstance(store, dict) 
     self.store = store 

    def __getitem__(self, key): 
     return self.store[key] 

我嘗試過這個類。據說在this doc中實現__getitem__應該足以讓我的測試類。事實上,當我試圖在國際熱核實驗堆,它並沒有告訴我,我不能,但我有一個KeyError異常python iter over dict-like object

In [10]: a = Test({1:1,2:2}) 

In [11]: for i in a: print i 
--------------------------------------------------------------------------- 
KeyError         Traceback (most recent call last) 
<ipython-input-11-8c9c9a8afa41> in <module>() 
----> 1 for i in a: print i 

<ipython-input-9-17212ae08f42> in __getitem__(self, key) 
     4   self.store = store 
     5  def __getitem__(self, key): 
----> 6   return self.store[key] 
     7 

KeyError: 0 
  • 你知道這個0是從哪裏來的?(這是怎麼回事引擎蓋下)

我知道我可以通過添加一個__iter__函數解決這個問題:

def __iter__(self): 
    return dict.__iter__(self.store) 
  • 是不是解決這個問題的最好方法?(我也可能繼承了字典類)。
+0

解決什麼問題的最好方法是什麼類應該做什麼?類只有'dict'的價值? –

回答

7

你錯過了文檔中的關鍵措辭,你發現:

對於序列類型,接受的按鍵應該是整數和切片對象。 [...] [I] F中的索引集爲序列(負值的任何特殊解釋之後)之外的值的,IndexError應提高。

注意for循環預期的IndexError將引發非法索引,以允許最終序列的的正確檢測。

大膽的斜體重點是我的。如果您接受密鑰,而不是整數,那麼您沒有序列。

Python術語解釋更多;看到definition of sequence

可迭代其支持通過__getitem__()特殊方法使用整數索引有效元素訪問並限定__len__()方法,它返回序列的長度。 請注意,dict也支持__getitem__()__len__(),但被認爲是映射而不是序列,因爲查找使用任意不可變的鍵而不是整數。

所以序列接受整數索引,這是迭代*時正是for提供。當給定要迭代的對象時,如果除了__getitem__之外沒有其他方法可用,則構造一個特殊的迭代器,其開始於0並且持續增加計數器直到IndexError被引發。在純Python中,將是:

def getitem_iterator(obj): 
    getitem = type(obj).__getitem__ # special method, so on the type 
    index = 0 
    try: 
     while True: 
      yield getitem(obj, index) 
      index += 1 
    except IndexError: 
     # iteration complete 
     return 

實際實現是在C中,請參閱PySeqIter_Type definition and functions

改爲執行__iter__ method;它存在時使用。既然你換一本字典,你可以簡單地返回迭代器該字典(使用iter() function而不是直接調用特殊的方法):

def __iter__(self): 
    return iter(self.store) 

*從技術上講,for不提供此。 for只是使用iter(obj)而且它是,它調用生成特殊迭代器,而沒有__iter__方法可用。