为什么在一个类上定义__getitem__可以在Python中迭代呢?
为什么在一个类上定义__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 c in cb:”
如果你看一下定义迭代器的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__
的支持可以被看作是一个“遗留特征”,当PEP234引入迭代作为一个主要概念时,允许更平滑的过渡。 它只适用于没有__iter__
的类,其__getitem__
接受整数0,1,&c,并且一旦索引变得太高(如果有的话),就会引发IndexError
,通常在__iter__
之前出现“sequence”类(尽pipe没有什么能阻止你编写新的类也是这样)。
就个人而言,我宁愿不要在新的代码中依赖这个,虽然它不被弃用,也不会消失(在Python 3中也能正常工作),所以这只是一个风格和品味的问题(“显式比隐式更好”我宁愿明确地支持迭代,而不是依赖__getitem__
为我隐式支持它 – 但不是一个bigge)。
__getitem__
早于迭代器协议,并且是过去使事物迭代的唯一方法。 因此,它仍然是一种迭代方法。 本质上,迭代的协议是:
-
检查一个
__iter__
方法。 如果存在,则使用新的迭代协议。 -
否则,请尝试调用具有更大整数值的
__getitem__
,直到引发IndexError。
(2)曾经是做这件事的唯一方法,但是有一个缺点,那就是它只是假设支持迭代而已。 为了支持迭代,你必须支持随机访问,这对于文件或者networkingstream等向前移动很容易的东西要昂贵得多,但是倒退则需要存储所有东西。 __iter__
没有随机访问的情况下允许迭代,但是由于随机访问通常允许迭代,而且由于反向兼容性不好, __getitem__
仍然被支持。
诸如__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
哪里对象是你在循环中迭代的东西。
这是历史原因。 在Python 2.2之前__getitem__是创build一个可以用for循环迭代的类的唯一方法。 在2.2中添加了__iter__协议,但保留向后兼容性__getitem__仍然在for循环中工作。
因为cb[0]
与cb.__getitem__(0)
。 看到这个python文档 。