50

Al integrar una aplicación Django que no había usado antes, encontré dos formas diferentes de definir funciones en las clases. El autor parece usar ambos de manera muy intencional. La primera de ellas es que yo mismo uso mucho:¿Cuándo debería usar @classmethod y when def method (self)?

class Dummy(object): 

    def some_function(self,*args,**kwargs): 
     do something here 
     self is the class instance 

La otra es que yo no uso, sobre todo porque no entiendo cuándo usarlo, y para qué:

class Dummy(object): 

    @classmethod 
    def some_function(cls,*args,**kwargs): 
     do something here 
     cls refers to what? 

en la documentación de Python classmethod el decorador se explica con esta frase:

un método de clase recibe la clase como primer argumento implícito, simplemente como un método de instancia recibe la instancia.

así que supongo que se refiere a clsDummy sí (el class, no el ejemplo). No entiendo exactamente por qué existe, porque siempre podría hacer esto:

type(self).do_something_with_the_class 

¿Es sólo por el bien de la claridad, o no se me olvida la parte más importante: las cosas espeluznantes y fascinantes que no podían ser hecho sin ella?

Respuesta

47

Su conjetura es correcta - usted entiende cómoclassmethod s trabajo.

El por qué es que estos métodos pueden ser llamados tanto en una instancia o en la clase (en ambos casos, la clase de objeto se pasa como primer argumento):

class Dummy(object): 

    @classmethod 
    def some_function(cls,*args,**kwargs): 
     print cls 

#both of these will have exactly the same effect 
Dummy.some_function() 
Dummy().some_function() 

Sobre el uso de estos en casos: Hay por lo menos dos usos principales para llamar a un classmethod en una instancia:

  1. self.some_function() llamará a la versión de some_function del tipo real de self, en lugar de los CLAS s en que esa llamada aparece (y no necesitará atención si se cambia el nombre de la clase); y
  2. En los casos en que some_function es necesario para implementar algún protocolo, pero es útil para llamar solo al objeto de clase.

La diferencia con staticmethod: Hay otra manera de definir los métodos que no tienen acceso a datos de instancia, llamados staticmethod. Eso crea un método que no recibe un primer argumento implícito; en consecuencia, no se pasará ninguna información sobre la instancia o clase en la que se llamó.

In [6]: class Foo(object): some_static = staticmethod(lambda x: x+1) 

In [7]: Foo.some_static(1) 
Out[7]: 2 

In [8]: Foo().some_static(1) 
Out[8]: 2 

In [9]: class Bar(Foo): some_static = staticmethod(lambda x: x*2) 

In [10]: Bar.some_static(1) 
Out[10]: 2 

In [11]: Bar().some_static(1) 
Out[11]: 2 

El uso principal que he encontrado para que consiste en adaptar una función existente (que no espera para recibir un self) que es un método de una clase (u objeto).

+1

Agradable: Me gusta que la respuesta se divida en cómo, por qué. Por lo que tengo, ahora @classmethod permite acceder a la función sin la necesidad de una instancia. Esto es exactamente lo que estaba buscando, gracias. – marue

+0

@marue ¡De nada! – Marcin

+0

Diría que llamar a los métodos de clase en instancias es un mal estilo de codificación, simplemente no hay razón para hacerlo y solo puede causar confusión. Pero sí, funciona (java permite lo mismo, pero emite una advertencia de compilación cuando llama a métodos estáticos a través de instancias) – Voo

0

Si agrega decorator @classmethod, eso significa que va a hacer ese método como método estático de java o C++.(el método estático es un término general Supongo ;)) Python también tiene @staticmethod. y la diferencia entre classmethod y staticmethod es si puede acceder a la clase o variable estática usando argumento o nombre de clase en sí.

class TestMethod(object): 
    cls_var = 1 
    @classmethod 
    def class_method(cls): 
     cls.cls_var += 1 
     print cls.cls_var 

    @staticmethod 
    def static_method(): 
     TestMethod.cls_var += 1 
     print TestMethod.cls_var 
#call each method from class itself. 
TestMethod.class_method() 
TestMethod.static_method() 

#construct instances 
testMethodInst1 = TestMethod()  
testMethodInst2 = TestMethod() 

#call each method from instances 
testMethodInst1.class_method() 
testMethodInst2.static_method() 

todas esas clases aumentan cls.cls_var en 1 y lo imprimen.

Y todas las clases que usen el mismo nombre en el mismo ámbito o instancias construidas con esta clase compartirán esos métodos. Sólo hay una TestMethod.cls_var y también hay una sola TestMethod.class_method(), TestMethod.static_method()

e importante cuestión. por qué se necesitaría este método.

classmethod o staticmethod es útil cuando haces esa clase como fábrica o cuando tienes que inicializar tu clase solo una vez. como abrir archivo una vez y usar el método de alimentación para leer el archivo línea por línea.

+1

(a) Los métodos estáticos son otra cosa; (b) los classmethods no son compartidos por todas las clases. – Marcin

+0

@Marcin gracias por dejarme saber mis definiciones poco claras y todo eso. –

Cuestiones relacionadas