2011-03-14 85 views
3

據我所知,我可以在__iter__方法的對象上使用for循環構造,該方法返回一個迭代器。我有我實現以下__getattribute__方法的對象:Python __iter__和for循環

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。

回答

12

有一個細微的實現細節在你的方式:__iter__實際上不是一個實例方法,而是一個類方法。即調用obj.__class__.__iter__(obj),而不是obj.__iter__()

這是由於插槽下的插槽優化,允許Python運行時更快地設置迭代器。這是必要的,因爲迭代器儘可能快是非常重要的。

無法爲class類型定義__getattribute__,因此無法動態返回此方法。這適用於大多數__metamethods__;你需要寫一個實際的包裝器。

+1

+1所以這就是爲什麼'iter'不叫'__getattribute__' ...正如他們所說,你每天都會在SO上學到新東西:) – delnan 2011-03-14 16:13:00

+0

+1和delnan說的。 – slezica 2011-03-14 16:19:13

+0

請注意,您可以看到此副作用(至少在CPython中):如果您定義了__getattribute__,那麼當您使用iter時會注意到它會被調用爲__class__,因爲運行時會查找要調用'__iter__'的對象的類。 (這應該被認爲是一個實現細節。) – 2011-03-14 16:58:20

4

某些特殊方法在創建類時優化,不能稍後添加或通過賦值重寫。見documentation__getattribute__它說:

這種方法仍可以繞過時 查找特殊的方法爲通過 語言的語法或內置函數隱式調用的 結果。

你需要在這種情況下,做的是提供一個直接執行的__iter__轉發該呼叫:

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