有人能解释一下Python中的hasattr/delattr在方法属性上的作用吗?
我遇到了一个奇怪的问题,可能是我对函数属性的理解有些偏差,或者这可能是个bug。我正在使用
$ 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
是什么时的“未绑定方法”。但我不确定这是否是一个预期的副作用,还是我理解错了什么,或者这真的是个bug。
2 个回答
5
你的问题其实不是出在函数属性上,而是实例方法和普通函数之间的区别。你可以试试:
class A(object):
def foo(self):
pass
foo.bar = 'magic'
del A.__dict__['foo'].bar
这样就可以正常工作了。原因在于这里你实际上获取的是函数对象 foo
,而不是实例方法 foo
。
在Python 3中,这种区别就不存在了,你所尝试的在实例方法上也能正常工作。想了解更多细节,可以查看这个邮件列表的讨论。
6
你应该这样做:
del Foo.bar.im_func.xyzzy
im_func
是用来访问真正的方法 Foo.bar
的,instancemethod
是一种装饰器,可以自动处理传递 self
的问题……。
根据我对你问题的理解,你之前成功地使用 getattr
来访问 Foo.bar
的 xyzzy
属性,但发现 delattr
的表现不一样。原因在于,内部 getattr
会调用类和对象的所有父类的 __getattribute__
(和 __getattr__
),直到找到这个属性或者抛出 AttributeError
。hasattr
的工作原理也是类似的,等同于:
def hasattr(obj, attr):
try:
getattr(obj, attr)
except AttributeError:
return False
return True
另一方面,delattr
只有在传入的属性是对象命名空间的一部分时才会成功(也就是说,不是它的类或父类的属性),这是出于安全考虑(你肯定不想尝试删除一个对象的属性,对吧 :-)。