2016-07-10 2 views
1

У меня есть следующий класс:Как использовать __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?

+2

[В дополнение к обходным атрибутам экземпляра в интересах корректности, неявный специальный поиск метода обычно также обходит метод '__getattribute __()' даже метакласса объекта] (https://docs.python.org/3/ reference/datamodel.html # special-method-lookup) –

ответ

3

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

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

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 

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

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

+1

Разница между реальным поиском и этим кодом на Python заключается в том, что приведенный выше код python можно манипулировать с помощью метаклассов, чтобы предоставить пользовательский '__dict__', в то время как реальный поиск обходит даже метакласса и получает доступ к отображению '__dict__' через прямое поле в базовой структуре C. – Bakuriu

+0

Это длинный файл, не могли бы вы дать мне номер строки или имя функции, пожалуйста? –

+1

@JonMcClung: ссылка идет прямо к функции, и я сказал, что имя функции - '_PyObject_LookupSpecial'. Большинство помощников, на которых он опирается, находятся в одном файле, поэтому вы можете найти их с помощью Ctrl-F. – user2357112

Смежные вопросы