В чем разница между "функцией", "методом" и "связанным методом" в Python 3?

Я наблюдал по крайней мере 3 типа, связанных с функциями в Python 3:

>>> class A():
...  def f(): pass
...
>>> A.f
<function A.f at 0x7fcaef304268>
>>> A().f
<bound method A.f of <__main__.A object at 0x7fcaef2fae80  
>>> set.union
<method 'union' of 'set' objects>

Мне интересно, в чем разница между "функция", "метод" и "связанный метод"? Является ли 'method' типом, эквивалентным 'unbound method' в Python 2?

1 ответ

Решение

Является ли 'method' типом, эквивалентным 'unbound method' в Python 2?

Kind-а-рода-а. Но не совсем. Это method_descriptor объект, определенный в коде C. Это несвязанный метод, но не тот, который вы нашли в Python 2.

Для типов Python, написанных на C, все "методы" на самом деле являются функциями C. <method 'name' of 'type' objects> объект, который вы нашли, является специальным объектом, который вы можете использовать для вызова этой функции с учетом экземпляра и дополнительных аргументов, как function Объект делает для пользовательских классов Python. Объект определен в C в PyMethodDescr_Type структура. Он реализует протокол дескриптора, как и функции.

Python определяет несколько других таких типов дескрипторов; если вы используете __slots__ каждый атрибут является дескриптором типа member_descriptor (см. PyMemberDescr_Type структура), в то время как classmethod, property а также staticmethod возможно более известные объекты дескриптора.

В Python 2 связанные и несвязанные методы на самом деле являются только одним типом, instancemethod (определяется PyMethod_Type структура); он будет сообщаться как связанный, если __self__ (im_self) атрибут установлен. В Python 3 использование функции в качестве дескриптора просто не создает объекты методов без __self__ задавать; вместо того, чтобы звонить function.__get__() без экземпляра просто возвращает функцию снова.

Единственная причина, по которой Python 2 возвращает несвязанные методы, - принудительная проверка типа; первый аргумент должен быть экземпляром класса (или его подклассом). Это не имело особого смысла для кода Python, который поддерживает типизацию с использованием утили, поэтому в Python 3 ограничение было снято. Тем не менее, с кодом C вы не можете использовать duck-typing, вам все равно придется ограничить тип, и поэтому C-типы по- прежнему возвращают method_descriptor объект, который применяет это ограничение.

Другие вопросы по тегам