2009-11-04 14 views
7

Tengo problemas para entender cómo funciona un objeto classmethod en Python, especialmente en el contexto de las metaclases y en __new__. En mi caso especial me gustaría obtener el nombre de un miembro classmethod, cuando repito el members que se dieron a __new__.¿Cómo funciona un objeto classmethod?

Para los métodos normales, el nombre simplemente se almacena en un atributo __name__, pero para un método de clase aparentemente no existe dicho atributo. Ni siquiera veo cómo se invoca el método de clase, ya que tampoco existe el atributo __call__.

Puede alguien explicarme cómo funciona un classmethod o que me señale alguna documentación? Google no me llevó a ninguna parte. ¡Gracias!

+0

No tengo información sobre el "faltante" '__name__', pero para estar seguro de que los classmethods tienen una envoltura' __call__'. – mjv

Respuesta

18

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' 
+0

¡Gracias, eso resolvió mi problema! Lo siento un poco estúpido ahora ya que, en principio, sabía acerca de los descriptores. Pero me confundí al ver que un método de clase está envuelto en un descriptor no llamable :-) – nikow

+0

Lo siento, me olvidé de enfatizar lo mucho que aprecio su respuesta detallada, esto es simplemente genial. – nikow

1

This parece que tiene las mercancías.

+0

Gracias, no conocía el término Metamethods, así que fue una lectura interesante. Pero me temo que no había mucha información sobre el objeto classmethod en sí. – nikow

Cuestiones relacionadas