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:
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)
- 这是解决这个问题的最佳方法吗?(我也可能继承自 dict 类)。
最佳答案
您在找到的文档中遗漏了一个关键措辞:
For sequence types, the accepted keys should be integers and slice objects. [...] [I]f of a value outside the set of indexes for the sequence (after any special interpretation of negative values),
IndexError
should be raised.Note:
for
loops expect that anIndexError
will be raised for illegal indexes to allow proper detection of the end of the sequence.
粗斜体强调是我的。如果您接受键,而不是整数,您就没有序列。
Python 词汇表解释更多;查看definition of sequence :
An iterable which supports efficient element access using integer indices via the
__getitem__()
special method and defines a__len__()
method that returns the length of the sequence. [...] Note thatdict
also supports__getitem__()
and__len__()
, but is considered a mapping rather than a sequence because the lookups use arbitrary immutable keys rather than integers.
所以序列接受整数索引,而这正是 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__
方法时,那个调用 产生特殊的迭代器可用。
关于python迭代类似dict的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40630678/