为什么在类上定义__getitem__使其可迭代?
例如,如果我写:
class b:
def __getitem__(self, k):
return k
cb = b()
for k in cb:
print k
我得到了输出:
0
1
2
3
4
5
6
7
8
...
我真的希望看到“for k in cb:”
返回错误答案 0 :(得分:60)
Iteration对__getitem__
的支持可被视为“遗留特征”,当PEP234引入可迭代性作为主要概念时,它允许更平滑的过渡。它仅适用于没有__iter__
的类__getitem__
接受整数0,1和c,并且一旦索引变得过高(如果有的话)就会引发IndexError
,通常是“序列”类在__iter__
出现之前编码(虽然没有什么能阻止你以这种方式编写新类)。
就个人而言,我宁愿在新代码中不依赖于它,虽然它不会被弃用,也不会消失(在Python 3中也可以正常工作),所以这只是风格和品味的问题(“明确优于隐含的“所以我宁愿明确地支持迭代,而不是依赖__getitem__
隐式支持它 - 但是,不是一个大的。”
答案 1 :(得分:46)
如果你看一下定义迭代器的PEP234,它会说:
1. An object can be iterated over with "for" if it implements
__iter__() or __getitem__().
2. An object can function as an iterator if it implements next().
答案 2 :(得分:25)
__getitem__
早于迭代器协议,并且过去只使用 方式使事物可迭代。因此,它仍然作为迭代方法得到支持。从本质上讲,迭代协议是:
检查__iter__
方法。如果存在,请使用新的迭代协议。
否则,尝试使用连续较大的整数值调用__getitem__
,直到它引发IndexError。
(2)曾经是这样做的唯一方法,但是它的缺点在于它假设比支持迭代所需的更多。为了支持迭代,你必须支持随机访问,这对于像前进很容易的文件或网络流这样的东西来说要贵得多,但倒退需要存储所有内容。 __iter__
允许迭代而无需随机访问,但由于随机访问通常允许迭代,并且因为破坏向后兼容性会很糟糕,所以仍然支持__getitem__
。
答案 3 :(得分:6)
__getitem__
等特殊方法向对象添加特殊行为,包括迭代。
http://docs.python.org/reference/datamodel.html#object.getitem
“for循环期望为非法索引引发IndexError,以允许正确检测序列的结尾。”
引发IndexError以表示序列的结束。
您的代码基本上等同于:
i = 0
while True:
try:
yield object[i]
i += 1
except IndexError:
break
对象就是你在for循环中迭代的对象。
答案 4 :(得分:5)
出于历史原因,这是如此。在Python 2.2之前,__ getitem__是创建可以使用for循环迭代的类的唯一方法。在2.2中添加了__iter__协议但是为了保持向后兼容性__getitem__仍然适用于for循环。
答案 5 :(得分:2)
因为cb[0]
与cb.__getitem__(0)
相同。请参阅此处的python documentation。