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

she*_*ats 177 python getproperty getattr

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

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

Mic*_*son 257

覆盖__getattr__应该没问题 - __getattr__只作为最后的手段调用,即如果实例中没有与名称匹配的属性.例如,如果您访问foo.bar,则__getattr__只有在foo没有调用属性的情况下才会被调用bar.如果属性是您不想处理的属性,请引发AttributeError:

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

但是,与之不同的是__getattr__,__getattribute__将首先调用(仅适用于新样式类,即从对象继承的类).在这种情况下,您可以保留默认行为,如下所示:

class Foo(object):
    def __getattribute__(self, name):
        if some_predicate(name):
            # ...
        else:
            # Default behaviour
            return object.__getattribute__(self, name)
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅Python文档.

  • 酷,Python似乎不喜欢在`__getattr__`中调用超级 - 任何想法该怎么做?(`AttributeError:'super'对象没有属性'__getattr __'`) (8认同)
  • -1 这*确实*修改默认行为。现在,您有一个“AttributeError”,但异常参数中没有属性的上下文。 (6认同)

小智 32

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))
Run Code Online (Sandbox Code Playgroud)
>>> 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
Run Code Online (Sandbox Code Playgroud)

  • 我认为应该使用`self .__ class __.__ name__`而不是`self .__ class__`,以防该类重写`__repr__` (4认同)
  • 这比接受的答案更好,但如果修改措辞或将来将额外的上下文添加到异常对象中,那么不必重写该代码并可能错过上游更改将是很好的. (2认同)

Jos*_*uis 10

要扩展迈克尔答案,如果要保持使用的默认行为__getattr__,可以这样做:

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

        # Default behaviour
        return self.__getattribute__(name)
Run Code Online (Sandbox Code Playgroud)

现在,异常消息更具描述性:

>>> 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'
Run Code Online (Sandbox Code Playgroud)

  • @ fed.pavlo你确定吗?也许你混合了`__getattr__`和`__getattribute__`? (2认同)
  • 如果没有这个答案,@Michael 的答案确实是不完整的 (2认同)