为什么getattr()不能像我认为的那样工作?我认为这段代码应该打印'sss'

时间:2009-12-27 02:36:10

标签: python

接下来是我的代码:

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而不是self.a ['a'],这显然不想看到

为什么,有没有办法避免它

2 个答案:

答案 0 :(得分:3)

您正在混淆getattr内置函数,它在运行时动态地(按名称)检索对象的某些属性绑定,以及__getattr__方法,当您访问某些对象时会调用该方法缺少对象的属性。

你不能问

if x in self:

来自__getattr__,因为in运算符会导致__getattr__被调用,从而导致无限递归。

如果您只想将未定义的属性全部定义为某个值,则

def __getattr__(self, ignored):
    return "Bob Dobbs"

答案 1 :(得分:3)

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

class foo:

意味着你要定义一种旧式的,也就是遗产的类,它的行为有时会相当古怪。永远不要那样做 - 没有充分的理由!旧式类仅存在与依赖于它们的怪癖的旧遗留代码的兼容性(并且最终在Python 3中被废除)。改为使用 new 样式类:

class foo(object):

然后检查if x in self:将不会导致递归__getattr__调用。然而, 会导致失败,因为您的类没有定义__contains__方法,因此您无法检查该类的实例中是否包含x

如果您要做的是x是否在self实例字典中定义,请不要打扰:__getattr__不要甚至在这种情况下被调用 - 只有当self中的属性为而不是时才会调用它。

要支持对getattr内置raise AttributeError的三个参数调用,必要时只需__getattr__方法__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

这样的“超级类实现的上调”(你也可以通过内置的{{1}}获得)是规则的罕见例外之一“不要直接调用特殊方法,调用内置函数在或使用运算符“ - 在这里,您希望专门绕过正常行为,因此显式特殊方法调用是可能的。