¿Cuál es la diferencia entre una ‘función’, un ‘método’ y un ‘método enlazado’ en Python 3?

He observado al menos 3 tipos relacionados con funciones en Python 3:

>>> class A(): ... def f(): pass ... >>> Af  >>> A().f <bound method Af of >> set.union  

Me pregunto cuál es la diferencia entre ‘función’, ‘método’ y ‘método enlazado’? ¿Es ‘método’ un tipo equivalente a ‘método no vinculado’ en Python 2?

¿Es ‘método’ un tipo equivalente a ‘método no vinculado’ en Python 2?

Un poco sorta. Pero no realmente. Es un objeto method_descriptor definido en el código C. Es un método independiente, pero no del tipo que se encontró en Python 2.

Para los tipos de Python escritos en C, todos los ‘métodos’ son realmente funciones de C. El objeto que encontró es un objeto especial que puede usar para llamar a esa función dada una instancia y otros argumentos, al igual que el objeto de function para las clases de Python personalizadas. El objeto se define en C en la estructura PyMethodDescr_Type . Implementa el protocolo descriptor , al igual que las funciones.

Python define varios otros tipos de descriptores similares; Si usa __slots__ , cada atributo es un dsescriptor de tipo member_descriptor (vea la estructura PyMemberDescr_Type ), mientras que el classmethod , property y staticmethod son quizás objetos descriptores más conocidos.

En Python 2, los métodos enlazados y no enlazados son en realidad solo un tipo, instancemethod (definido por la estructura PyMethod_Type ); se informará como enlazado si el __self__ ( im_self ) está establecido. En Python 3, usar una función como descriptor simplemente no produce objetos de método sin el conjunto __self__ ; en su lugar, llamar a la function.__get__() sin instancia, simplemente devuelve la función nuevamente.

La única razón por la que Python 2 devuelve métodos no vinculados es para imponer una verificación de tipo ; el primer argumento debe ser una instancia de la clase (o una subclase de la misma). Esto no tenía mucho sentido para el código de Python que admite la escritura de pato, por lo que en Python 3 se eliminó la restricción. Sin embargo, con el código C no puede utilizar la tipificación duck, todavía tiene que restringir el tipo, y esa es la razón por la que los tipos C aún devuelven un objeto method_descriptor que impone esta restricción.