假设您使用包装器对象:
class IterOrNotIter:
def __init__(self):
self.f = open('/tmp/toto.txt')
def __getattr__(self, item):
try:
return self.__getattribute__(item)
except AttributeError:
return self.f.__getattribute__(item)
这个对象实现了__iter__
,因为它将对它的任何调用都传递给实现它的成员f
。恰当的例子:
>>> x = IterOrNotIter()
>>> x.__iter__().__next__()
'Whatever was in /tmp/toto.txt\n'
根据文档 ( https://docs.python.org/3/library/stdtypes.html#iterator-types ),IterOrNotIter 因此应该是可迭代的。
但是,Python 解释器无法将 IterOrNotIter
对象识别为实际可迭代对象:
>>> x = IterOrNotIter()
>>> for l in x:
... print(l)
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'IterOrNotIter' object is not iterable
虽然这是可行的:
>>> x = IterOrNotIter()
>>> for l in x.f:
... print(l)
...
Whatever was in /tmp/toto.txt
我不明白为什么。
最佳答案
基本上是因为你的类没有真正的 __iter__
方法:
>>> hasattr(IterOrNotIter, '__iter__')
False
所以它不符合迭代器的条件,因为对 __iter__
的实际检查是检查是否存在,而不是假设它已实现。因此,使用 __getattr__
或 __getattribute__
的解决方法(不幸的是)不起作用。
__getattribute__
的文档中实际上提到了这一点:
Note
This method may still be bypassed when looking up special methods as the result of implicit invocation via language syntax or built-in functions. See Special method lookup.
后一部分还解释了原因:
Bypassing the
__getattribute__()
machinery in this fashion provides significant scope for speed optimisations within the interpreter, at the cost of some flexibility in the handling of special methods (the special method must be set on the class object itself in order to be consistently invoked by the interpreter).
强调我的。
关于python - 为什么实现了 __iter__ 的对象不被识别为可迭代的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43935187/