Skip to main content
 首页 » 编程设计

python之为什么 getattr() 没有像我认为的那样工作我认为这段代码应该打印 'sss'

2025年05月04日18dflying

接下来是我的代码:

class foo: 
    def __init__(self): 
        self.a = "a" 
    def __getattr__(self,x,defalut): 
        if x in self: 
            return x 
        else:return defalut 
 
a=foo() 
print getattr(a,'b','sss') 

我知道 __getattr__ 必须是 2 个参数,但如果属性不存在,我想获取默认属性。

如何获取,谢谢


和

我发现如果定义了__setattr__,我的下一段代码也无法运行

class foo: 
    def __init__(self): 
        self.a={} 
    def __setattr__(self,name,value): 
            self.a[name]=value 
 
a=foo()#error ,why 

嗨,亚历克斯, 我改变了你的例子:

class foo(object): 
    def __init__(self): 
        self.a = {'a': 'boh'} 
    def __getattr__(self, x): 
        if x in self.a: 
            return self.a[x] 
        raise AttributeError 
 
a=foo() 
print getattr(a,'a','sss') 

它打印{'a': 'boh'},而不是'boh' 我认为它会打印 self.a not self.a['a'], 这显然是不想看到的

为什么,有什么办法可以避免吗

请您参考如下方法:

您的第一个问题:您正在定义一个旧式类(我们知道您使用的是 Python 2.something,即使您没有告诉我们,因为您正在使用 print 作为关键字;-)。在 Python 2 中:

class foo: 

意味着您正在定义一个旧式的,也就是传统的类,其行为有时可能相当古怪。永远不要那样做——没有充分的理由!旧式类的存在只是为了与依赖于它们的怪癖的旧遗留代码兼容(并最终在 Python 3 中被废除)。改用新样式类:

class foo(object): 

然后检查 if x in self: 不会导致递归 __getattr__ 调用。但是无论如何它都会导致失败,因为您的类没有定义__contains__ 方法,因此您无法检查实例中是否包含x那个类的。

如果你想做的是 x 是否在 self 的 instance dict 中定义,请不要打扰:__getattr__ 在这种情况下甚至不会被调用——只有当属性不 否则在 self 中找到时才会被调用。

要支持对内置的 getattr 的三参数调用,如有必要,只需在 __getattr__ 方法中 raise AttributeError(就像将如果您根本没有 __getattr__ 方法,就会发生这种情况),内置函数将完成它的工作(内置 的工作是拦截这种情况并返回如果提供默认)。这就是为什么人们从不直接调用 __getattr__ 等特殊方法,而是使用在内部调用它们的内置函数和运算符的原因——内置函数和运算符提供了大量的附加值。

举个比较有道理的例子:

class foo(object): 
    def __init__(self): 
        self.blah = {'a': 'boh'} 
    def __getattr__(self, x): 
        if x in self.blah: 
            return self.blah[x] 
        raise AttributeError 
 
a=foo() 
print getattr(a,'b','sss') 

这会根据需要打印 sss。

如果您添加一个__setattr__ 方法,那个 方法会拦截每次 尝试在self 上设置属性——包括 self.blah = 什么的。所以——当你需要绕过你正在定义的 __setattr__ 时——你必须使用不同的方法。例如:

class foo(object): 
    def __init__(self): 
        self.__dict__['blah'] = {} 
    def __setattr__(self, name, value): 
        self.blah[name] = value 
    def __getattr__(self, x): 
        if x in self.blah: 
            return self.blah[x] 
        raise AttributeError 
 
a=foo() 
print getattr(a,'b','sss') 

这也会打印 sss。而不是

        self.__dict__['blah'] = {} 

你也可以用

        object.__setattr__(self, 'blah', {}) 

这种“对父类(super class)实现的调用”(您也可以通过内置的 super 获得)是“不要直接调用特殊方法,调用内置或改用运算符”——在这里,您想要专门绕过正常行为,因此可以进行显式特殊方法调用。