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__应该足以胜过我的Test类。事实上,当我试图通过它时,它并没有告诉我我不能,但我有一个 KeyError :
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
我知道我可以通过添加__iter__函数来解决它:
def __iter__(self):
return dict.__iter__(self.store)
答案 0 :(得分:7)
您错过了您找到的文档中的重要措辞:
对于 序列类型 ,接受的键应为整数和切片对象。 [...] [I] f除了序列 之外的值 (在对负值进行任何特殊解释之后) ,
IndexError
应该被提出。注意:
for
循环期望为非法索引引发IndexError
以允许正确检测序列的结尾 强>
大胆的斜体重点是我的。如果您接受键而不是整数,则表示您没有序列。
Python词汇表解释更多;请参阅definition of sequence:
一个iterable,它通过
__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__
方法可用时,调用生成特殊迭代器。