Python中的__iter__与for循环
根据我的理解,我可以在一个有 __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__
;你需要写一个实际的包装器。