Как использовать getattr для делегирования методов атрибутам?


У меня есть следующий класс:

class MyInt:
    def __init__(self, v):
        if type(v) != int:
            raise ValueError('value must be an int')
        self.v = v

    def __getattr__(self, attr):
        return getattr(self.v, attr)

i = MyInt(0)
print(i + 1)

Я получаю ошибку: TypeError: unsupported operand type(s) for +: 'MyInt' and 'int'

Не следует ли вызвать i.__add__(1)? И не следует ли вызывать __getattr__, когда такой метод не найден в классе MyInt?

1 2

1 ответ:

__getattr__ Нельзя использовать для создания других магических методов. Вам нужно будет реализовать их все по отдельности.

Когда внутренние части языка Python ищут магические методы, такие как __add__, они полностью обходят __getattr__, __getattribute__, и пример диктует. Поиск идет примерно так:

def find_magic_method(object, method_name):
    for klass in type(object).__mro__:
        if method_name in klass.__dict__:
            return klass.__dict__[method_name]
    raise AttributeError

Если вы хотите увидеть точную процедуру поиска, это _PyObject_LookupSpecial в Objects/typeobject.c.

Если вам интересно, почему Python делает это, есть много магических методов, для которых это было бы действительно неловко или невозможно сделать то, что вы ожидали. Например, Python не может использовать __getattribute__ для поиска __getattribute__, так как это вызовет бесконечную рекурсию без базового случая.