staticmethod - que es cls en python




¿Significado de @classmethod y @staticmethod para principiante? (8)

¿Podría alguien explicarme el significado de @classmethod y @staticmethod en python? Necesito saber la diferencia y el significado.

Según tengo entendido, @classmethod le dice a una clase que es un método que debe heredarse en subclases, o ... algo. Sin embargo, ¿cuál es el punto de eso? ¿Por qué no definir el método de la clase sin agregar @classmethod o @staticmethod o ninguna de las definiciones @ ?

tl; dr: ¿ cuándo debo usarlos, por qué debo usarlos y cómo debo usarlos?

Estoy bastante avanzado con C ++, por lo que usar conceptos de programación más avanzados no debería ser un problema. Siéntase libre de darme un ejemplo correspondiente de C ++ si es posible.


¿Significado de @classmethod y @staticmethod ?

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

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

No necesitas ninguno de los dos decoradores. Pero en 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 error de tipo, pero no entender la semántica de ese argumento es un error del usuario.

(Definir some_function , 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 punteada en una instancia en este orden: buscamos:

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

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

instance = Example()
instance.regular_instance_method 

Y los métodos son atributos exigibles:

instance.regular_instance_method()

métodos de instancia

El argumento, self , se da implícitamente a través de la búsqueda de puntos.

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

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

métodos de clase

El argumento, cls , se da implícitamente a través de la búsqueda por 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 implícitamente argumentos. 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

Una vez más, ¿cuándo debo usarlos, por qué debo usarlos?

Cada uno de estos son progresivamente más restrictivos en la información que pasan el método versus los métodos de instancia.

Úsalos cuando no necesites la información.

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

¿Sobre cuál es más fácil de 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 probar.

Estos son similares a la instancia, la clase y los métodos estáticos. Teniendo en cuenta que cuando tenemos una instancia, también tenemos su clase, una vez más, pregúntese, ¿cuál es más fácil de 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:

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

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

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

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

Cuando se hace una subclase, vemos que obtiene la información de 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 como un constructor. (No codificarías la clase para que las subclases pudieran usarse aquí).


Cuándo usar cada

@staticmethod función @staticmethod no es más que una función definida dentro de una clase. Se puede llamar sin instanciar la clase primero. Su definición es inmutable a través de la herencia.

  • Python no tiene que crear una instancia de un método enlazado para el objeto.
  • Facilita la legibilidad del código: al ver el método @estático , sabemos que el método no depende del estado del objeto en sí;

@classmethod función @classmethod también se puede @classmethod sin crear una instancia de la clase, pero su definición sigue a Subclase, no a la Clase principal, por herencia, se puede anular por subclase. Esto se debe a que el primer argumento para la función @classmethod siempre debe ser cls (class) .

  • Métodos de fábrica , que se utilizan para crear una instancia para una clase utilizando, por ejemplo, algún tipo de preprocesamiento.
  • Métodos estáticos que llaman a métodos estáticos : si divide los métodos estáticos en varios métodos estáticos, no debe codificar el nombre de la clase, sino usar los métodos de clase.

here hay un buen enlace a este tema.


El método de clase puede modificar el estado de la clase, se vincula a la clase y contiene cls como parámetro.

El método estático no puede modificar el estado de la clase, está vinculado a la clase y no conoce la clase o la instancia

class empDetails:
    def __init__(self,name,sal):
        self.name=name
        self.sal=sal
    @classmethod
    def increment(cls,name,none):
        return cls('yarramsetti',6000 + 500)
    @staticmethod
    def salChecking(sal):
        return sal > 6000

emp1=empDetails('durga prasad',6000)
emp2=empDetails.increment('yarramsetti',100)
# output is 'durga prasad'
print emp1.name
# output put is 6000
print emp1.sal
# output is 6500,because it change the sal variable
print emp2.sal
# output is 'yarramsetti' it change the state of name variable
print emp2.name
# output is True, because ,it change the state of sal variable
print empDetails.salChecking(6500)

En resumen, @classmehtod convierte un método normal a un método de fábrica.

Explorémoslo con un ejemplo:

class PythonBook:
    def __init__(self, name, author):
        self.name = name
        self.author = author
    def __repr__(self):
        return f'Book: {self.name}, Author: {self.author}'

Sin un método de clase @, deberías trabajar para crear instancias una por una y se ejecutarán con un scart.

book1 = PythonBook('Learning Python', 'Mark Lutz')
In [20]: book1
Out[20]: Book: Learning Python, Author: Mark Lutz
book2 = PythonBook('Python Think', 'Allen B Dowey')
In [22]: book2
Out[22]: Book: Python Think, Author: Allen B Dowey

Como por ejemplo con @classmethod

class PythonBook:
    def __init__(self, name, author):
        self.name = name
        self.author = author
    def __repr__(self):
        return f'Book: {self.name}, Author: {self.author}'
    @classmethod
    def book1(cls):
        return cls('Learning Python', 'Mark Lutz')
    @classmethod
    def book2(cls):
        return cls('Python Think', 'Allen B Dowey')

Pruébalo:

In [31]: PythonBook.book1()
Out[31]: Book: Learning Python, Author: Mark Lutz
In [32]: PythonBook.book2()
Out[32]: Book: Python Think, Author: Allen B Dowey

¿Ver? Las instancias se crean correctamente dentro de una definición de clase y se recopilan juntas.

En conclusión, @classmethod decorator convierte un método convencional a un método de fábrica. El uso de classmethods hace posible agregar tantos constructores alternativos como sea necesario.


Soy un principiante en este sitio, he leído todas las respuestas anteriores y obtuve la información que quiero. Sin embargo, no tengo derecho a votar. Así que quiero comenzar con con la respuesta tal como la entiendo.

  • @staticmethod no necesita self o cls como primer parámetro del método
  • @staticmethod funciones @staticmethod y @classmethod se pueden llamar por instancia o variable de clase
  • @staticmethod función decorada de @staticmethod afecta a una especie de 'propiedad inmutable' que la herencia de subclase no puede sobrescribir en su función de clase base que está envuelta por un decorador de @staticmethod .
  • @classmethod need cls (Nombre de la clase, puede cambiar el nombre de la variable si lo desea, pero no se recomienda) como el primer parámetro de la función
  • @classmethod siempre se usa de manera subclase, la herencia de subclase puede cambiar el efecto de la función de clase base, es decir, la función de clase base envuelta @classmethod podría ser sobrescrita por diferentes subclases.

Una forma ligeramente diferente de pensar que podría ser útil para alguien ... Un método de clase se usa en una superclase para definir cómo debe comportarse ese método cuando es llamado por diferentes clases secundarias. Se usa un método estático cuando queremos devolver lo mismo independientemente de la clase secundaria a la que estamos llamando.


@classmethod significa: cuando se llama a este método, pasamos la clase como primer argumento en lugar de la instancia de esa clase (como normalmente hacemos con los métodos). Esto significa que puede usar la clase y sus propiedades dentro de ese método en lugar de una instancia en particular.

@staticmethod significa: cuando se llama a este método, no le pasamos una instancia de la clase (como normalmente hacemos con los métodos). Esto significa que puede poner una función dentro de una clase pero no puede acceder a la instancia de esa clase (esto es útil cuando su método no usa la instancia).


Un poco de compilación

@staticmethod Una forma de escribir un método dentro de una clase sin referencia al objeto al que se está llamando. Así que no hay necesidad de pasar argumentos implícitos como self o cls. Se escribe exactamente de la misma manera que se escribe fuera de la clase, pero no es de ninguna utilidad en Python porque si necesita encapsular un método dentro de una clase, ya que este método debe ser parte de esa clase, @staticmethod es muy útil. caso.

@classmethod Es importante cuando desea escribir un método de fábrica y, por este atributo (s) personalizado (s), se puede adjuntar en una clase. Este atributo (s) puede ser anulado en la clase heredada.

Una comparación entre estos dos métodos puede ser la siguiente





class-method