如何在不破坏默认行为的情况下覆盖Python中的__getattr__?

时间:2010-03-08 23:29:32

标签: python getattr getproperty

我想覆盖类上的__getattr__方法来做一些奇特的事情,但我不想打破默认行为。

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

3 个答案:

答案 0 :(得分:248)

覆盖__getattr__应该没问题 - __getattr__仅作为最后手段调用,即如果实例中没有与名称匹配的属性。例如,如果您访问foo.bar,则只有在__getattr__没有名为foo的属性时才会调用bar。如果属性是您不想处理的属性,请引发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

答案 1 :(得分:31)

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__.__name__, attr))

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

答案 2 :(得分:8)

要扩展迈克尔答案,如果您想使用__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'