Python __iter__ 和 for 循环

Posted

技术标签:

【中文标题】Python __iter__ 和 for 循环【英文标题】:Python __iter__ and for loops 【发布时间】:2011-07-15 03:10:47 【问题描述】:

据我了解,我可以在对象上使用for 循环构造,并使用返回迭代器的__iter__ 方法。我有一个对象,我为此实现了以下__getattribute__ 方法:

def __getattribute__(self,name):
    if name in ["read","readlines","readline","seek","__iter__","closed","fileno","flush","mode","tell","truncate","write","writelines","xreadlines"]:
        return getattr(self.file,name)
    return object.__getattribute__(self,name)

我有一个此类的对象,a,它会发生以下情况:

>>> hasattr(a,"__iter__")
True
>>> for l in a: print l
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'TmpFile' object is not iterable
>>> for l in a.file: print l
...
>>>

所以python看到a有一个__iter__方法,但不认为它是可迭代的。我做错了什么?这是python 2.6.4。

【问题讨论】:

【参考方案1】:

有一个微妙的实现细节妨碍了你:__iter__ 实际上不是一个实例方法,而是一个类方法。也就是说,调用的是obj.__class__.__iter__(obj),而不是obj.__iter__()

这是由于底层的槽优化,允许 Python 运行时更快地设置迭代器。这是必需的,因为迭代器尽可能快是非常重要的。

无法为底层class 类型定义__getattribute__,因此无法动态返回此方法。这适用于大多数__metamethods__;您需要编写一个实际的包装器。

【讨论】:

+1 这就是为什么iter 不打电话给__getattribute__...正如他们所说,你每天都会在 SO 上学到新东西 :) 请注意,您可以看到它的副作用(至少在 CPython 中):如果您定义 __getattribute__,您会注意到当您使用 iter 时它会被调用为 __class__ ,因为运行时查找对象的类以调用__iter__。 (这可能应该被认为是一个实现细节。)【参考方案2】:

某些特殊方法在创建类时进行了优化,以后无法添加或通过赋值覆盖。请参阅documentation 中的__getattribute__,其中说:

这个方法仍然可以被绕过 查找特殊方法作为 通过隐式调用的结果 语言语法或内置函数。

在这种情况下,您需要做的是提供 __iter__ 的直接实现来转发呼叫:

def __iter__(self):
    return self.file.__iter__()

【讨论】:

以上是关于Python __iter__ 和 for 循环的主要内容,如果未能解决你的问题,请参考以下文章

for循环的本质

Learn Python—函数(迭代器生成器)

python——函数18迭代器

python函数(迭代器,生成器)

python开发基础迭代器和生成器

Python 迭代器/生成器