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

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

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

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

Является ли «метод» эквивалентным типу «несвязанный метод» в Python 2?

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

Для типов Python, написанных C, все «методы» – это действительно C-функции. Объект <method 'name' of 'type' objects> object, который вы нашли, является специальным объектом, который вы можете использовать для вызова этой функции с учетом экземпляра и дополнительных аргументов, как и объект 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__ объект метода без __self__ set; вместо вызова function.__get__() без экземпляра, просто возвращает функцию снова.

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