2009-12-27 41 views
1

下一个是我的代码:为什么getattr()不能像我认为的那样工作?我认为此代码应打印“SSS”

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') 

它打印{“一”:“嘘”},而不是“嘘” 我认为这将打印self.a不self.a [“一”],这显然不希望看到

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

+0

Downvoted不听的答案。 – 2009-12-27 13:14:47

+1

@zjm,不,没有办法让'getattr(self,'a',whatever)'**避免**获得'self.a'的时候,当然这也不是很明显,为什么一个人想要。你为什么不重新命名属性,对'self .__ a'说,如果你想从外面隐藏它? – 2009-12-27 15:31:14

回答

3

你的头号问题:您定义旧式类(我们知道你在Python的2 .something,即使你不告诉我们,因为你使用print作为关键字;-)。在Python 2:

class foo: 

意味着你定义一个老式的,又名遗产类,其行为可以是相当古怪的时间。永远不要那样做 - 没有理由!旧式类只存在于与依赖于其怪癖的旧遗留代码兼容(并且最终在Python 3中被废除)。使用样式类来代替:

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获得) “不要直接调用特殊的方法,而是调用内置的或者使用操作符” - 在这里,你想专门绕过正常的行为,所以明确的特殊方法调用是可能的。

+0

嗨亚历克斯,我改变你的例子 it print {'a':'boh'},而不是'boh'我认为它会打印self.a而不是self.a ['a'], – zjm1126 2009-12-27 07:33:38

3

你混淆getattr内置函数,它提取一些属性的对象(按名称)动态绑定,在运行时,与__getattr__方法,这是在访问对象的某些缺失属性时调用。

你不能要求

if x in self: 
__getattr__

,因为in操作会导致__getattr__被调用,从而导致无限递归。

如果你只是想有未定义的属性都被定义为一定的价值,然后

def __getattr__(self, ignored): 
    return "Bob Dobbs" 
相关问题