2010-03-08 44 views
152

我想覆盖类的__getattr__方法做一些奇特的事情,但我不想打破默认行为。如何在不违反默认行为的情况下在Python中覆盖__getattr__?

这样做的正确方法是什么?

+20

“休息”,它问,而不是“改变”。这足够清楚:“奇特”属性不应该干扰内置属性,并应尽可能像他们那样表现。迈克尔的回答既正确又有帮助。 – olooney 2010-03-09 00:04:03

回答

228

覆盖__getattr__应该没问题 - __getattr__仅作为最后手段被调用,即如果实例中没有与该名称匹配的属性。例如,如果您访问foo.bar,则仅在foo没有称为bar的属性时才会调用__getattr__。如果属性是一个你不想来处理,提高AttributeError

class Foo(object): 
    def __getattr__(self, name): 
     if some_predicate(name): 
      # ... 
     else: 
      # Default behaviour 
      raise AttributeError 

然而,不同于__getattr____getattribute__称为第一(仅适用于新的样式类,即那些从对象继承)。在这种情况下,您可以保留默认行为,如下所示:

class Foo(object): 
    def __getattribute__(self, name): 
     if some_predicate(name): 
      # ... 
     else: 
      # Default behaviour 
      return object.__getattribute__(self, name) 

请参阅the Python docs for more

+0

Bah,您的编辑与我在回答中显示的内容相同+1。 – 2010-03-08 23:51:34

+7

很酷,Python似乎不喜欢在'__getattr__'中调用super - 任何想法该怎么办? ('AttributeError:'super'对象没有属性'__getattr __'') – gatoatigrado 2013-06-11 23:33:59

+1

没有看到你的代码很难说,但看起来你的超类没有定义__getattr__。 – 2015-04-11 16:00:47

26
class A(object): 
    def __init__(self): 
    self.a = 42 

    def __getattr__(self, attr): 
    if attr in ["b", "c"]: 
     return 42 
    raise AttributeError("%r object has no attribute %r" % 
         (self.__class__, attr)) 
    # exception text copied from Python2.6 

>>> a = A() 
>>> a.a 
42 
>>> a.b 
42 
>>> a.missing 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 8, in __getattr__ 
AttributeError: 'A' object has no attribute 'missing' 
>>> hasattr(a, "b") 
True 
>>> hasattr(a, "missing") 
False 
+0

谢谢你。只是想确保我有正确的默认消息,而不需要在源代码中进行挖掘。 – ShawnFumo 2013-11-04 17:48:47

+2

我认为应该使用'self .__ class __.__ name__'来代替'self .__ class__',以防类重写'__repr__' – 2016-01-11 20:46:33

2

为了延长迈克尔回答,如果你想保持使用__getattr__默认行为,你可以像这样:

class Foo(object): 
    def __getattr__(self, name): 
     if name == 'something': 
      return 42 

     # Default behaviour 
     return self.__getattribute__(name) 

现在异常消息是更具描述:

>>> foo.something 
42 
>>> foo.error 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 5, in __getattr__ 
AttributeError: 'Foo' object has no attribute 'error' 
+1

@ fed.pavlo您确定吗?也许你把'__getattr__'和'__getattribute__'混合了? – 2016-09-16 07:41:32

+0

我的不好。我错过了来自不同方法的来电。 ( – 2016-09-19 10:18:06

相关问题