Un objeto classmethod
es un descriptor. Debes entender cómo funcionan las descripciones.
En pocas palabras, un descriptor es un objeto que tiene un método __get__
, que tiene tres argumentos: self
, un instance
, y un instance type
.
Durante la búsqueda normal de atributos, si un objeto buscado A
tiene un método __get__
, se llama a ese método y lo que devuelve se sustituye en su lugar por el objeto A
. Así es como las funciones (que también son descriptores) se convierten en métodos vinculados cuando se llama a un método en un objeto.
class Foo(object):
def bar(self, arg1, arg2):
print arg1, arg2
foo = Foo()
# this:
foo.bar(1,2) # prints '1 2'
# does about the same thing as this:
Foo.__dict__['bar'].__get__(foo, type(foo))(1,2) # prints '1 2'
A classmethod
objeto funciona de la misma manera. Cuando se lo busca, se llama al método __get__
. El __get__
de un classmethod descarta el argumento correspondiente a la instance
(si había uno) y sólo pasa a lo largo de la instance_type
cuando llama __get__
en la función envuelto.
Un doodle ilustrativa:
In [14]: def foo(cls):
....: print cls
....:
In [15]: classmethod(foo)
Out[15]: <classmethod object at 0x756e50>
In [16]: cm = classmethod(foo)
In [17]: cm.__get__(None, dict)
Out[17]: <bound method type.foo of <type 'dict'>>
In [18]: cm.__get__(None, dict)()
<type 'dict'>
In [19]: cm.__get__({}, dict)
Out[19]: <bound method type.foo of <type 'dict'>>
In [20]: cm.__get__({}, dict)()
<type 'dict'>
In [21]: cm.__get__("Some bogus unused string", dict)()
<type 'dict'>
Más información sobre los descriptores se puede encontrar aquí (entre otros lugares): http://users.rcn.com/python/download/Descriptor.htm
para la tarea específica de conseguir el nombre de la función envuelta por un classmethod
:
In [29]: cm.__get__(None, dict).im_func.__name__
Out[29]: 'foo'
No tengo información sobre el "faltante" '__name__', pero para estar seguro de que los classmethods tienen una envoltura' __call__'. – mjv