¿Cuándo debo usar @classmethod y cuándo def method(self)?


Al integrar una aplicación Django que no he usado antes, encontré dos formas diferentes de definir funciones en clases. El autor parece usarlos a ambos muy intencionalmente. El primero es uno que yo mismo uso mucho:

class Dummy(object):

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

El otro es uno que no uso, principalmente 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 los documentos de Python, el decorador classmethod se explica con esta oración:

Un método de clase recibe la clase como implícita primer argumento, solo como un método de instancia recibe la instancia.

Así que supongo que cls se refiere a Dummy en sí (el class, no la instancia). No entiendo exactamente por qué existe esto, porque siempre podría hacer esto:

type(self).do_something_with_the_class

¿Es esto solo por el bien de la claridad, o me perdí la parte más importante: cosas espeluznantes y fascinantes que no se podrían hacer sin ella?

Author: P̲̳x͓L̳, 2012-05-14

2 answers

Tu suposición es correcta-entiendes cómo classmethods trabajo.

El porqué es que estos métodos pueden ser invocados tanto en una instancia COMO en la clase (en ambos casos, el objeto de clase será pasado 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 instancias: Hay al menos dos usos principales para llamar a un classmethod en una instancia:

  1. self.some_function() llamará a la versión de some_function en el tipo real de self, en lugar de la clase 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 implementar algún protocolo, pero es útil llamar solo al objeto de la clase.

La diferencia con staticmethod: Hay otra forma de definir métodos que no acceden a datos de instancia, llamada staticmethod. Que crea un método que no recibe un primer argumento implícito en absoluto; en consecuencia, no se pasará ninguna información sobre el instancia o clase en la que fue llamado.

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 ello es adaptar una función existente (que no espera recibir un self) para que sea un método en una clase (u objeto).

 54
Author: Marcin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-14 17:11:48

Si agregas decorator @classmethod, eso significa que vas a hacer que ese método sea un método estático de java o C++. (método estático es un término general Supongo ;) ) Python también tiene @staticmethod. y la diferencia entre classmethod y staticmethod es si se puede acceso a la clase o variable estática usando el propio argumento o classname.

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 por 1 e imprimirlo.

Y cada clase usando el mismo nombre en el mismo ámbito o las instancias construidas con estas clases van a compartir esos métodos. Sólo hay un método de prueba.cls_var y también hay un solo método de prueba.class_method (), TestMethod.static_method ()

Y una pregunta importante. por qué estos métodos serían necesarios.

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

 0
Author: Ryan Kim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-14 17:07:15