Страницы

Поиск по вопросам

среда, 29 января 2020 г.

Магические методы

#python #ооп #python_internals


Как реализована архитектура магических методов в python?
Например:

class SomeClass:
    def __init__(self, x):
        self.x = x

    def __repr__(self):
        return "({})".format(self.x)

a = SomeClass(23)
print(repr(a))


Т.е. как происходит определние вызова нужного метода нужного класса? (repr класса
SomeClass)?
    


Ответы

Ответ 1



Немного дополню предыдущие ответы. Согласно официальной документации, вот тут, специальные методы (именно так называются магические методы в документации) это подход python к перегрузке операторов, позволяющий классам определять свое поведение в отношении операторов языка. Из этого можно заключить, что интерпретатор имеет "некую таблицу" (назовём это так) соответствия операторов к методам класса. Перегружая эти методы, вы можете управлять "поведением" операторов языка относительно вашего класса. Также, если в некотором классе сделать любой специальный (магический) метод None, то это будет означать, что данная операция для некоторого класса не доступна, а соответствующий оператор, применённый к этому классу, вернет TypeError. Сигнатуру функции repr для СPython, вы можете посмотреть только в исходниках на С. В модуле builtins.py она выглядит следующим образом def repr(obj): # real signature unknown; restored from __doc__ """ Return the canonical string representation of the object. For many object types, including most builtins, eval(repr(obj)) == obj. """ pass Но думаю тут и так понятно. Создавая свой класс без наследников, вы неявно наследуете класс object со всеми его специальными методами включая и repr. В модуле builtins.py это выглядит так: class object: """ The most base type """ .... # ещё порядка 20 магических методов def __repr__(self, *args, **kwargs): # real signature unknown """ Return repr(self). """ pass Таким образом можно сделать, ещё один вывод, что даже "пустой" пользовательский класс, готов для применения, в том или ином виде, операторами (функциями) языка. И ещё немного о соответствии тут

Ответ 2



Магический метод — это просто метод, который вызывается неявно, часто чтобы выполнить операцию для типа. К примеру, можно определить __bool__ метод, чтобы указать является ли объект True/False в булевом контексте (если поведение по умолчанию, основанное на __len__ или True, не подходит). Очень многие аспекты поведения объектов в Питоне могут быть изменены таким образом. К примеру, plumbum модуль, за счёт перегрузки операторов, встраивает sh-подобный язык прямо в Питон: #!/usr/bin/env python from plumbum.cmd import awk, sort (awk["-f", "script.awk"] << "input data" | sort > "outfile.txt")() Как реализована архитектура магических методов в python? Как происходит определение вызова нужного метода нужного класса? repr(SomeClass()) приводит к вызову SomeClass.__repr__ (если определён), потому что документация repr() функции так говорит. В целом, ничего особенно не происходит, к примеру, вы можете свой протокол определить: def quack(obj): return getattr(obj, 'quack', None)() Любой объект, для которого определён метод quack(), независимо от его базовых классов, можно передать в функцию quack(): class Duck: def quack(self): return "Quack! Quack! Quack!" print(quack(Duck())) Для остальных классов TypeError выбрасывается: try: quack(1) except TypeError: print("целое число не квакает") Отличие quack() от настоящих магических методов, что не используется двойное подчёркивание в имени метода, по соглашению, зарезервированное для протоколов, определяемых самим языком и нет требования определить метод в самом классе (определения из Мета-класса или присваивание метода объекту напрямую могут не работать для магических методов): >>> class C: ... pass >>> c = C() >>> c.__len__ = lambda: 0 >>> len(c) Traceback (most recent call last): File "", line 1, in TypeError: object of type 'C' has no len() Для сравнения, quack() можно прямо самому объекту присвоить: >>> c.quack = lambda: "ga ga" >>> quack(c) 'ga ga' Но чтобы len() работала, необходимо определение в сам класс помещать: >>> class C: ... def __len__(self): ... return 0 >>> len(C()) 0 Это сделано для оптимизации скорости вызова подобных методов и чтобы избежать "metaclass confusion", описанную выше по ссылке. В CPython, почти все специальные методы (термин для магических методов из спецификации языка) хранятся в специальных слотах в типе.

Ответ 3



посмотрите на этот вопрос так def __repr__(self): return "({x})".format(x=self.x) class SomeClass:pass a = SomeClass() a.x = 23 print(__repr__(a))

Комментариев нет:

Отправить комментарий