in

python – ¿Significado de @classmethod y @staticmethod para principiantes?

apple touch icon@2

El significado de @classmethod y @staticmethod?

  • Un método es una función en el espacio de nombres de un objeto, accesible como atributo.
  • Un método regular (es decir, instancia) obtiene la instancia (generalmente la llamamos self) como primer argumento implícito.
  • A clase el método obtiene la clase (normalmente lo llamamos cls) como primer argumento implícito.
  • A estático El método no obtiene un primer argumento implícito (como una función regular).

¿Cuándo debo usarlos, por qué debo usarlos y cómo debo usarlos?

Tu no necesitar cualquier decorador. Pero según el principio de que debe minimizar el número de argumentos de las funciones (consulte Clean Coder), son útiles para hacer precisamente eso.

class Example(object):

    def regular_instance_method(self):
        """A function of an instance has access to every attribute of that 
        instance, including its class (and its attributes.)
        Not accepting at least one argument is a TypeError.
        Not understanding the semantics of that argument is a user error.
        """
        return some_function_f(self)

    @classmethod
    def a_class_method(cls):
        """A function of a class has access to every attribute of the class.
        Not accepting at least one argument is a TypeError.
        Not understanding the semantics of that argument is a user error.
        """
        return some_function_g(cls)

    @staticmethod
    def a_static_method():
        """A static method has no information about instances or classes
        unless explicitly given. It just lives in the class (and thus its 
        instances') namespace.
        """
        return some_function_h()

Tanto para los métodos de instancia como para los métodos de clase, no aceptar al menos un argumento es un TypeError, pero no comprender la semántica de ese argumento es un error del usuario.

(Definir some_functiones, por ejemplo:

some_function_h = some_function_g = some_function_f = lambda x=None: x

y esto funcionará.)

búsquedas de puntos en instancias y clases:

Se realiza una búsqueda de puntos en una instancia en este orden; buscamos:

  1. un descriptor de datos en el espacio de nombres de la clase (como una propiedad)
  2. datos en la instancia __dict__
  3. un descriptor que no es de datos en el espacio de nombres de la clase (métodos).

Tenga en cuenta que una búsqueda con puntos en una instancia se invoca así:

instance = Example()
instance.regular_instance_method 

y los métodos son atributos invocables:

instance.regular_instance_method()

métodos de instancia

El argumento, self, se proporciona implícitamente mediante la búsqueda de puntos.

Debe acceder a los métodos de instancia desde las instancias de la clase.

>>> instance = Example()
>>> instance.regular_instance_method()
<__main__.Example object at 0x00000000399524E0>

métodos de clase

El argumento, cls, se proporciona implícitamente mediante una búsqueda de puntos.

Puede acceder a este método a través de una instancia o la clase (o subclases).

>>> instance.a_class_method()
<class '__main__.Example'>
>>> Example.a_class_method()
<class '__main__.Example'>

métodos estáticos

No se dan argumentos implícitos. Este método funciona como cualquier función definida (por ejemplo) en el espacio de nombres de un módulo, excepto que se puede buscar

>>> print(instance.a_static_method())
None

Nuevamente, ¿cuándo debería usarlos, por qué debería usarlos?

Cada uno de estos son progresivamente más restrictivos en la información que transmiten al método frente a los métodos de instancia.

Úselos cuando no necesite la información.

Esto hace que sus funciones y métodos sean más fáciles de razonar y realizar pruebas unitarias.

¿Sobre cuál es más fácil razonar?

def function(x, y, z): ...

o

def function(y, z): ...

o

def function(z): ...

Las funciones con menos argumentos son más fáciles de razonar. También son más fáciles de realizar pruebas unitarias.

Estos son similares a los métodos de instancia, clase y estáticos. Teniendo en cuenta que cuando tenemos una instancia, también tenemos su clase, nuevamente, pregúntate, ¿sobre cuál es más fácil razonar ?:

def an_instance_method(self, arg, kwarg=None):
    cls = type(self)             # Also has the class of instance!
    ...

@classmethod
def a_class_method(cls, arg, kwarg=None):
    ...

@staticmethod
def a_static_method(arg, kwarg=None):
    ...

Ejemplos incorporados

Aquí hay un par de mis ejemplos incorporados favoritos:

los str.maketrans El método estático era una función en el string módulo, pero es mucho más conveniente que sea accesible desde el str espacio de nombres.

>>> 'abc'.translate(str.maketrans({'a': 'b'}))
'bbc'

los dict.fromkeys El método de clase devuelve un nuevo diccionario instanciado a partir de un iterable de claves:

>>> dict.fromkeys('abc')
{'a': None, 'c': None, 'b': None}

Cuando se subclasifica, vemos que obtiene la información de la clase como un método de clase, lo cual es muy útil:

>>> class MyDict(dict): pass
>>> type(MyDict.fromkeys('abc'))
<class '__main__.MyDict'> 

Mi consejo – Conclusión

Use métodos estáticos cuando no necesite los argumentos de clase o instancia, pero la función está relacionada con el uso del objeto y es conveniente que la función esté en el espacio de nombres del objeto.

Use métodos de clase cuando no necesite información de instancia, pero necesite la información de clase tal vez para su otra clase o métodos estáticos, o tal vez él mismo como constructor. (No codificaría la clase para que las subclases se puedan usar aquí).

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

60 102992 1559633846

¿Qué significa el operador de doble signo de interrogación (??) en PHP?

owjSmimvFZUywYVbnjZstC 1200 80

El póster de Mandalorian con Luke entrenando a Grogu hace que los fanáticos de Star Wars hablen