Python中的__iter__与for循环

3 投票
2 回答
1936 浏览
提问于 2025-04-16 13:40

根据我的理解,我可以在一个有 __iter__ 方法的对象上使用 for 循环,这个方法会返回一个迭代器。我有一个对象,我为它实现了以下的 __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 的环境下。

2 个回答

4

有些特殊的方法在创建类的时候就已经优化好了,之后不能再添加或者通过赋值来覆盖。你可以查看文档,里面提到关于__getattribute__的方法:

在通过语言语法或内置函数隐式调用时,查找特殊方法时可能仍然会绕过这个方法。

在这种情况下,你需要直接实现__iter__方法,并将调用转发到其他地方:

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

这里有个细节可能让你感到困惑:__iter__ 其实不是一个实例方法,而是一个类方法。也就是说,调用的是 obj.__class__.__iter__(obj),而不是 obj.__iter__()

这是因为在背后有一些优化,让 Python 运行时能够更快地设置迭代器。迭代器的速度非常重要,所以这种优化是必要的。

对于底层的 class 类型,无法定义 __getattribute__,所以不能动态返回这个方法。这种情况适用于大多数 __metamethods__;你需要写一个实际的包装器。

撰写回答