2011-08-06 60 views
3

我有一個奇怪的行爲造成的錯誤。我可能從根本上忽略了關於函數屬性的語義。或者它可能是一個錯誤。我在有人可以解釋方法屬性上的Python hasattr/delattr嗎?

$ python 
Python 2.7.1+ (r271:86832, Apr 11 2011, 18:13:53) 
[GCC 4.5.2] on linux2 

首先我定義一個類,併爲它的一個方法添加一個屬性。現在

>>> class Foo(object): 
... def bar(self): 
...  pass 
... bar.xyzzy = 'magic' 
... 

我可以看到存在於Foo.bar

>>> hasattr(Foo.bar, 'xyzzy') 
True 

而且我可以找回。

>>> Foo.bar.xyzzy 
'magic' 

>>> getattr(Foo.bar, 'xyzzy') 
'magic' 

但我無法刪除它。

>>> del Foo.bar.xyzzy 
Traceback (most recent call last): 
    ... 
AttributeError: 'instancemethod' object has no attribute 'xyzzy' 

>>> delattr(Foo.bar, 'xyzzy') 
Traceback (most recent call last): 
    ... 
AttributeError: 'instancemethod' object has no attribute 'xyzzy' 

任何想法爲什麼?我認爲這與Foo.bar在此處被報告爲「實例方法」這一事實有關,而不是如果您只是詢問Foo.bar是什麼的未綁定方法。但我不確定這是否是預期的副作用,如果我誤解了某些內容,或者是否有錯誤。

回答

6

你應該這樣做:

del Foo.bar.im_func.xyzzy 

im_func是需要訪問真正的方法Foo.barinstancemethod是一種裝飾,與自動過分自我......對付的。


正如我可能從你的問題了解你的同時使用getattr成功訪問的Foo.barxyzzy屬性和你一樣碰到一個事實,即delattr不採取行動以同樣的方式,而其原因是在內部getattr呼叫類的__getattribute__(和__getattr__)和所有父類中,直到它找到屬性或引發AttributeError,同樣對於hasattr的第一個參數的物體的這相當於:

def hasattr(obj, attr): 
    try: 
     getattr(obj, attr) 
    except AttributeError: 
     return False 
    return True 

在另一方面delattr如果傳遞的屬性是因爲安全的原因,對象名稱空間(不his class無論他的父母類)的一部分,纔會成功(你不想(嘗試)刪除的屬性object你不會:-)。

+0

完美,感謝您的解決方案。 – Ian

5

您的問題不在於函數屬性,它與實例方法和函數之間存在差異。嘗試:

class A(object): 
    def foo(self): 
     pass 
    foo.bar = 'magic' 

del A.__dict__['foo'].bar 

它會正常工作。這是因爲在這裏,你實際上得到函數對象foo,而不是實例方法foo

這個區別在Python 3中沒有了,你試着在實例方法上工作得很好。詳情請參閱this mailing list thread

+0

感謝agf,特別是郵件列表主題鏈接。 – Ian