__getattr__ 和 getattr 之间有什么关系?

40 投票
3 回答
16676 浏览
提问于 2025-04-15 17:16

我知道这段代码是对的:

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 个回答

19

__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 了!

40

getattr 是一个内置函数,它至少需要两个参数:一个是你想要获取属性的对象,另一个是属性的名字(以字符串形式给出)。

如果属性名是一个常量,比如 'foo',那么 getattr(obj, 'foo')obj.foo完全一样的

所以,getattr 这个内置函数的主要用途是当你没有属性名作为常量,而是作为一个变量的时候。第二个重要的用途是当你传入三个参数,而不仅仅是两个:在这种情况下,如果对象中没有这个属性,getattr 会返回第三个“默认”参数,而不是抛出错误。

__getattr__ 是一个特殊的方法,它是在一个类中定义的,当你请求这个类的某个实例的属性时,如果通过实例的 __dict__、插槽、属性等正常方式都找不到这个属性,就会调用这个方法。你可以定义它,比如当你想把未定义的属性查找委托给其他对象时。

所以你第二个例子是错误的,因为内置的 getattr 永远 不能只用一个参数。

第三个例子失败是因为你试图从一个字典中“获取一个属性”,但这个字典并没有那个属性——它有,而这些和属性是完全不同的。

64

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则用来获取这些属性

撰写回答