Документ модели данных Python: несвязанный пользовательский объект метода и объект метода класса - PullRequest
3 голосов
/ 01 февраля 2012

В Модель данных ссылки, писатель потратил много усилий, объясняя, как Пользовательские методы создаются и работают: (См. http://docs.python.org/reference/datamodel.html#the-standard-type-hierarchy и сверните вниз)

Пользовательские объекты метода могут быть созданы при получении атрибута класса (возможно, через экземпляр этого класса), , если это Атрибут является определяемым пользователем объектом функции, несвязанный определяемый пользователем объект метода или объект метода класса. Когда атрибут является определяемый пользователем объект метода, новый объект метода создается только в том случае, если класс, из которого он извлекается, совпадает с class, класс хранится в исходном объекте метода; иначе, оригинальный объект метода используется как есть.

Так в чем же разница между несвязанным определяемым пользователем объектом метода и объектом метода класса ?

1 Ответ

6 голосов
/ 01 февраля 2012

С точки зрения «пользователя», метод класса в Python - это метод, который получает свой класс в качестве своего первого параметра - в отличие от «обычных» методов, которые получают экземпляр класса в качестве своего первого параметра - который по соглашениюnamed self.

Если вы извлекаете «обычный» метод из класса, а не из объекта этого класса, вы получаете «несвязанный метод» - т.е. объект, который является оберткой для функции, но это автоматически не добавляет ни сам класс, ни какой-либо экземпляр в качестве первого параметра при его вызове.Поэтому, если вы хотите вызвать «несвязанный метод», вы должны вручную передать экземпляр его класса в качестве первого параметра.

Если вы вручную вызываете метод класса, с другой стороны, класс заполняетсяв качестве первого параметра для вас:

>>> class A(object):
...   def b(self):
...      pass
...   @classmethod
...   def c(cls):
...      pass
... 
>>> A.b
<unbound method A.b>
>>> A.c
<bound method type.c of <class '__main__.A'>>
>>> A.c()
>>> A.b()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method b() must be called with A instance as first argument (got nothing instead)
>>> 

Под капотом то, что происходит более или менее так - с "новыми классами стилей":

Когда определяется тело класса, методыэто просто обычные функции - когда тело класса закончено, Python вызывает метакласс класса (который обычно является встроенным type) - и передает ему в качестве параметров имя, базовые классы и словарь тела класса.Этот вызов дает класс - который в Python является объектом, который является классом, поскольку все является объектом.

Теперь у Python есть несколько изящных способов настройки доступа к атрибутам - так называемые «дескрипторы».Дескриптор - это любой объект, который определяет метод с именем __get__ (или __set__ или __del__, но нас это не волнует).Когда кто-то обращается к атрибуту класса или объекта в Python, возвращается объект, на который ссылается этот атрибут, за исключением случаев, когда это атрибут класса, а объект является дескриптором.В этом случае вместо возврата самого объекта Python вызывает метод __get__ для этого объекта и возвращает его результаты.Например, встроенный property - это просто класс, который реализует __set__, __get__ и __del__ в зависимости от ситуации.

Теперь, что происходит при извлечении атрибута, так это то, что любойФункция (или метод класса, или несвязанный метод, как утверждает модель данных) в своем теле имеет метод __get__, который делает его дескриптором.По сути, дескриптор, который при каждом доступе к атрибуту для извлечения объекта, названного функцией, как это определено в теле функции, создает новый объект вокруг этой функции - объект, который при вызове будет автоматически заполнять первый параметр, которыйскажем, method.

Пример.

>>> class B(object):
...    def c(self):
...      pass
...    print c
... 
<function c at 0x1927398>
>>> print B.c
<unbound method B.c>
>>> b = B()
>>> b.c
<bound method B.c of <__main__.B object at 0x1930a10>

Если вы хотите получить объект функции, без преобразования в объект метода, вы можете сделать это через класс *Атрибут 1031 *, который не вызывает дескриптор:

>>> B.__dict__["c"]
<function c at 0x1927398>
>>> B.__dict__["c"].__get__
<method-wrapper '__get__' of function object at 0x1927398>
>>> B.__dict__["c"].__get__(b, B)
<bound method B.c of <__main__.B object at 0x1930a10>>
>>> B.__dict__["c"].__get__(None, B)
<unbound method B.c>

Что касается «методов класса», то это просто объекты другого типа, которые явно декорированы встроенным classmethod - Возвращаемый объекткогда вызывается __get__, это обертка вокруг исходной функции, которая заполнит cls в качестве первого параметра при вызове.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...