Как переопределить __getattr__ в Python, не нарушая поведение по умолчанию? - PullRequest
169 голосов
/ 09 марта 2010

Я хочу переопределить метод __getattr__ в классе, чтобы сделать что-то необычное, но я не хочу нарушать поведение по умолчанию.

Как правильно это сделать?

Ответы [ 3 ]

250 голосов
/ 09 марта 2010

Переопределение __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)

См. документы по Python для получения дополнительной информации .

32 голосов
/ 09 марта 2010
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
8 голосов
/ 11 августа 2015

Чтобы расширить ответ Михаэля, если вы хотите сохранить поведение по умолчанию, используя __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'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...