为什么在类上定义 __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:”返回错误
为什么在类上定义 __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:”返回错误
__getitem__
当 PEP234 将可迭代性作为主要概念引入时,迭代对 的支持可以被视为“遗留功能”,它允许更平滑的过渡。它仅适用于不接受整数 0、1 和 c__iter__
的类,并且一旦索引变得太高(如果有的话)就会引发,通常是在出现之前编码的“序列”类(尽管没有什么能阻止你以这种方式编码新类)。__getitem__
IndexError
__iter__
就个人而言,我宁愿不要在新代码中依赖它,尽管它没有被弃用也不会消失(在 Python 3 中也可以正常工作),所以这只是风格和品味的问题(“显式优于隐式”所以我宁愿明确地支持可迭代性,而不是依赖于__getitem__
隐含地支持它——但是,不是很大)。
如果您看一下定义迭代器的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().
__getitem__
早于迭代器协议,并且在过去是使事物可迭代的唯一方法。因此,它仍然被支持作为一种迭代方法。本质上,迭代的协议是:
检查__iter__
方法。如果存在,请使用新的迭代协议。
否则,尝试__getitem__
使用连续更大的整数值调用,直到引发 IndexError。
(2) 曾经是这样做的唯一方法,但缺点是它假设了支持迭代所需的更多内容。为了支持迭代,您必须支持随机访问,这对于文件或网络流之类的东西来说要昂贵得多,因为它们向前很容易,但向后移动则需要存储所有内容。 __iter__
允许没有随机访问的迭代,但由于随机访问通常允许迭代,并且因为破坏向后兼容性会很糟糕,__getitem__
所以仍然支持。
特殊方法,例如__getitem__
向对象添加特殊行为,包括迭代。
http://docs.python.org/reference/datamodel.html#object。获取项目
“for 循环期望会为非法索引引发 IndexError,以允许正确检测序列的结尾。”
引发 IndexError 表示序列结束。
您的代码基本上相当于:
i = 0
while True:
try:
yield object[i]
i += 1
except IndexError:
break
其中 object 是您在 for 循环中迭代的内容。
之所以如此,是因为历史原因。在 Python 2.2 之前,__getitem__ 是创建可以用 for 循环迭代的类的唯一方法。在 2.2 中添加了 __iter__ 协议,但为了保持向后兼容性 __getitem__ 仍然适用于 for 循环。
因为cb[0]
是一样的cb.__getitem__(0)
。请参阅有关此的python 文档。