2011-03-24 227 views
2

我想在一个类(python2.7)中自定义属性访问。说我定义了以下类:Python属性访问错误

class testAttrAccess(object): 
    def __init__(self): 
     self.data = {"attr1":"value1","attr2":"value2"} 

    def __getattr__(self,name): 
     try: 
      return self.data[name] 
     except KeyError: 
      pass 

     raise AttributeError 

然后我得到:

In [85]: a = testAttrAccess() 

In [86]: a.attr2 
Out[86]: 'value2' 

In [87]: a.__getattr__('attr2') 
Out[87]: 'value2' 

In [88]: a.__getattribute__('attr2') 
--------------------------------------------------------------------------- 
AttributeError       Traceback (most recent call last) 

/Users/laserson/temp/<ipython console> in <module>() 

AttributeError: 'testAttrAccess' object has no attribute 'attr2' 

然而,according to the python documentation

如果该类还定义__getattr__(),后者将不会被调用,除非__getattribute__()要么明确地调用它或引发AttributeError

所以,如果__getattribute__()是提高了AttributeError,那么为什么不__getattr__()被调用和返回正确的价值?

回答

1

__getattribute__()仍然是默认的,所以它是深远的self.attr2而不是self.data['attr2']

+0

哦,但为什么'a.attr2'作品。 maybes thats not it ...好问题 – 2011-03-24 19:48:46

+0

'a.attr2'的工作原理恰恰是因为'attr2'不存在,因此'__getattr__'被调用。而默认的'__getattribute__'显然不会调用'__getattr__'。 – delnan 2011-03-24 20:10:03

+0

对,我按照。感谢您的澄清,我第二次猜测我自己一分钟 – 2011-03-25 05:12:36

0

a.__getattr__如果属性不是a.__dict__发现被称为只。

a.__getattribute__在所有情况下都会调用,如果已定义。

如你所知,a.__getattribute__(attr)type(a).__getattribute__(a, attr)语法糖,但由于这种方法不testAttrAccess定义,父类的方法object.__getattribute__(a, attr)被调用。从你的结果中,我们可以得出结论,它不是object.__getattribute__,它调用__getattr__。解释者可能会照顾到这一点。

你可以通过改变它像这样使你的工作方案:

class testAttrAccess(object): 
    def __init__(self): 
     self.data = {"attr1": "value1", "attr2": "value2"} 

    def __getattribute__(self, name): 
     try: 
      return object.__getattribute__(self, name) 
     except AttributeError: 
      if name == "__getattr__": 
       return object.__getattribute__(self, "__getattribute__") 
     try: 
      return object.__getattribute__(self, "data")[name] 
     except KeyError: 
      raise AttributeError 
a = testAttrAccess() 

print a.attr2 
print a.__getattr__('attr2') 
print a.__getattribute__('attr2') 
print a.qwerty 

输出:

 
value2 
value2 
value2 
Traceback (most recent call last): 
    File "test.py", line 20, in 
    print a.qwerty 
    File "test.py", line 13, in __getattribute__ 
    raise AttributeError 
AttributeError 
+0

我的印象是,每当想要覆盖属性访问以执行默认操作以外的操作时,他们应该只覆盖'__getattr __()'而不是'__getattribute __( )'。它是否正确?上面提出的实施有没有隐藏的副作用? – 2011-03-24 22:45:32

+0

请参阅我贡献的答案。我将不胜感激任何评论。 – 2011-03-24 23:12:37

1
So if __getattribute__() is raising an AttributeError, then why isn't __getattr__() being called and returning the proper value? 

如果蟒蛇呼吁__getattribute__你作为正常的一部分,但只适用属性访问,如果你自己调用__getattribute__则不行。基本上,你应该差不多永远不会调用形式为__foo__的python方法。这些方法用于实现依赖于其他操作的行为。

0

受@lazyr启发,这个解决方案似乎也起作用。这对我来说似乎更简单......是否会给任何人提供任何红旗?

class testAttrAccess(object): 
    def __init__(self): 
     self.data = {"attr1":"value1","attr2":"value2"} 

    def __getattribute__(self,name): 
     try: 
      return object.__getattribute__(self,name) 
     except AttributeError: 
      pass 

     try: 
      return self.data[name] 
     except KeyError: 
      pass 

     raise AttributeError 

以下的会议使:

In [108]: a = testAttrAccess() 

In [109]: a.attr2 
Out[109]: 'value2' 

In [110]: a.__getattribute__('attr2') 
Out[110]: 'value2' 

In [111]: a.__getattr__('attr2') 
--------------------------------------------------------------------------- 
AttributeError       Traceback (most recent call last) 

/Users/laserson/temp/<ipython console> in <module>() 

/Users/laserson/temp/<ipython console> in __getattribute__(self, name) 

AttributeError: 

In [112]: a.qwerty 
--------------------------------------------------------------------------- 
AttributeError       Traceback (most recent call last) 

/Users/laserson/temp/<ipython console> in <module>() 

/Users/laserson/temp/<ipython console> in __getattribute__(self, name) 

AttributeError: 
+0

'__getattribute__'被称为*每个非魔术方法('__add__','__repr__'等),所以会有很大的性能打击,以及对于你想要的东西完全没有必要 - 你的原始代码使用'__getattr__'适合你想要做的事情。 – 2011-11-03 23:04:00