__getattr__ 和 getattr 之间有什么关系?
我知道这段代码是对的:
class A:
def __init__(self):
self.a = 'a'
def method(self):
print "method print"
a = A()
print getattr(a, 'a', 'default')
print getattr(a, 'b', 'default')
print getattr(a, 'method', 'default')
getattr(a, 'method', 'default')()
而这段代码是错的:
# will __getattr__ affect the getattr?
class a(object):
def __getattr__(self,name):
return 'xxx'
print getattr(a)
这段代码也是错的:
a={'aa':'aaaa'}
print getattr(a,'aa')
那么我们应该在什么情况下使用 __getattr__
和 getattr
呢?
3 个回答
__getattr__()
是一个特殊的方法,你可以自己定义。当你试图查找一个成员(比如变量或方法)但找不到时,这个函数就会被调用。
getattr()
是一个你可以使用的函数,用来尝试查找一个成员。如果查找成功,你就能得到这个成员(可能是一个方法,也可能是一个数据属性)。如果查找失败,getattr()
还可以返回一个默认值。
如果你定义了一个 __getattr__()
方法,你可以让它在某些情况下成功,或者让它每次都成功。
class A(object):
def __getattr__(self, name):
return "I pretend I have an attribute called '%s'" % name
a = A()
print a.foo # prints "I pretend I have an attribute called 'foo'"
Python 还有一个 __getattribute__()
方法,它在每次查找时都会被调用。这是非常危险的,因为它可能会导致你无法正常访问成员。
class A(object):
def __init__(self, value):
self.v = value
def __getattribute__(self, name):
return "I pretend I have an attribute called '%s'" % name
a = A(42)
print a.v # prints "I pretend I have an attribute called 'v'"
print a.__dict__["v"] # prints "I pretend I have an attribute called '__dict__'"
哎呀,现在无法访问 a.v 了!
getattr
是一个内置函数,它至少需要两个参数:一个是你想要获取属性的对象,另一个是属性的名字(以字符串形式给出)。
如果属性名是一个常量,比如 'foo'
,那么 getattr(obj, 'foo')
和 obj.foo
是完全一样的。
所以,getattr
这个内置函数的主要用途是当你没有属性名作为常量,而是作为一个变量的时候。第二个重要的用途是当你传入三个参数,而不仅仅是两个:在这种情况下,如果对象中没有这个属性,getattr
会返回第三个“默认”参数,而不是抛出错误。
__getattr__
是一个特殊的方法,它是在一个类中定义的,当你请求这个类的某个实例的属性时,如果通过实例的 __dict__
、插槽、属性等正常方式都找不到这个属性,就会调用这个方法。你可以定义它,比如当你想把未定义的属性查找委托给其他对象时。
所以你第二个例子是错误的,因为内置的 getattr
永远 不能只用一个参数。
第三个例子失败是因为你试图从一个字典中“获取一个属性”,但这个字典并没有那个属性——它有项,而这些和属性是完全不同的。
Alex的回答很好,不过因为你问了,所以我给你提供一个示例代码 :)
class foo:
def __init__(self):
self.a = "a"
def __getattr__(self, attribute):
return "You asked for %s, but I'm giving you default" % attribute
>>> bar = foo()
>>> bar.a
'a'
>>> bar.b
"You asked for b, but I'm giving you default"
>>> getattr(bar, "a")
'a'
>>> getattr(bar, "b")
"You asked for b, but I'm giving you default"
简单来说,答案是
你可以使用
__getattr__
来定义如何处理那些找不到的属性
而
getattr
则用来获取这些属性