¿Métodos estáticos en Python?

Resuelto Joan Venge asked hace 15 años • 12 respuestas

¿ Puedo definir un método estático al que pueda llamar directamente en la instancia de clase? p.ej,

MyClass.the_static_method()
Joan Venge avatar Apr 10 '09 04:04 Joan Venge
Aceptado

Sí, usando el staticmethoddecorador:

class MyClass(object):
    @staticmethod
    def the_static_method(x):
        print(x)

MyClass.the_static_method(2)  # outputs 2

Tenga en cuenta que parte del código podría utilizar el método antiguo de definir un método estático, utilizándolo staticmethodcomo función en lugar de decorador. Esto sólo debe usarse si tiene que soportar versiones antiguas de Python (2.2 y 2.3):

class MyClass(object):
    def the_static_method(x):
        print(x)
    the_static_method = staticmethod(the_static_method)

MyClass.the_static_method(2)  # outputs 2

Esto es completamente idéntico al primer ejemplo (usando @staticmethod), solo que no usa la sintaxis agradable del decorador.

Por último, ¡úsalo staticmethodcon moderación! Hay muy pocas situaciones en las que los métodos estáticos son necesarios en Python, y los he visto utilizados muchas veces donde una función separada de "nivel superior" hubiera sido más clara.


Lo siguiente es textual de la documentación :

Un método estático no recibe un primer argumento implícito. Para declarar un método estático, utilice este modismo:

class C:
    @staticmethod
    def f(arg1, arg2, ...): ...

El formulario @staticmethod es un decorador de funciones ; consulte la descripción de las definiciones de funciones en Definiciones de funciones para obtener más detalles.

Se puede llamar en la clase (como C.f()) o en una instancia (como C().f()). La instancia se ignora excepto su clase.

Los métodos estáticos en Python son similares a los que se encuentran en Java o C++. Para un concepto más avanzado, consulte classmethod().

Para obtener más información sobre los métodos estáticos, consulte la documentación sobre la jerarquía de tipos estándar en La jerarquía de tipos estándar .

Nuevo en la versión 2.2.

Modificado en la versión 2.4: se agregó la sintaxis del decorador de funciones.

dbr avatar Apr 09 '2009 21:04 dbr

Creo que Steven tiene razón . Para responder a la pregunta original, entonces, para configurar un método de clase, simplemente asuma que el primer argumento no será una instancia de llamada y luego asegúrese de llamar solo al método desde la clase.

(Tenga en cuenta que esta respuesta se refiere a Python 3.x. En Python 2.x obtendrá un TypeErrorpara llamar al método en la clase misma).

Por ejemplo:

class Dog:
    count = 0 # this is a class variable
    dogs = [] # this is a class variable

    def __init__(self, name):
        self.name = name #self.name is an instance variable
        Dog.count += 1
        Dog.dogs.append(name)

    def bark(self, n): # this is an instance method
        print("{} says: {}".format(self.name, "woof! " * n))

    def rollCall(n): #this is implicitly a class method (see comments below)
        print("There are {} dogs.".format(Dog.count))
        if n >= len(Dog.dogs) or n < 0:
            print("They are:")
            for dog in Dog.dogs:
                print("  {}".format(dog))
        else:
            print("The dog indexed at {} is {}.".format(n, Dog.dogs[n]))

fido = Dog("Fido")
fido.bark(3)
Dog.rollCall(-1)
rex = Dog("Rex")
Dog.rollCall(0)

En este código, el método "rollCall" supone que el primer argumento no es una instancia (como lo sería si fuera llamado por una instancia en lugar de una clase). Siempre que se llame a "rollCall" desde la clase en lugar de una instancia, el código funcionará bien. Si intentamos llamar a "rollCall" desde una instancia, por ejemplo:

rex.rollCall(-1)

sin embargo, provocaría que se generara una excepción porque enviaría dos argumentos: él mismo y -1, y "rollCall" solo está definido para aceptar un argumento.

Por cierto, rex.rollCall() enviaría el número correcto de argumentos, pero también provocaría que se generara una excepción porque ahora n representaría una instancia de Dog (es decir, rex) cuando la función espera que n sea numérico.

Aquí es donde entra en juego la decoración: si antecedemos al método "rollCall" con

@staticmethod

luego, al indicar explícitamente que el método es estático, podemos incluso llamarlo desde una instancia. Ahora,

rex.rollCall(-1)

trabajaría. La inserción de @staticmethod antes de la definición de un método evita que una instancia se envíe a sí misma como argumento.

Puede verificar esto probando el siguiente código con y sin la línea @staticmethod comentada.

class Dog:
    count = 0 # this is a class variable
    dogs = [] # this is a class variable

    def __init__(self, name):
        self.name = name #self.name is an instance variable
        Dog.count += 1
        Dog.dogs.append(name)

    def bark(self, n): # this is an instance method
        print("{} says: {}".format(self.name, "woof! " * n))

    @staticmethod
    def rollCall(n):
        print("There are {} dogs.".format(Dog.count))
        if n >= len(Dog.dogs) or n < 0:
            print("They are:")
            for dog in Dog.dogs:
                print("  {}".format(dog))
        else:
            print("The dog indexed at {} is {}.".format(n, Dog.dogs[n]))


fido = Dog("Fido")
fido.bark(3)
Dog.rollCall(-1)
rex = Dog("Rex")
Dog.rollCall(0)
rex.rollCall(-1)
Richard Ambler avatar Apr 18 '2012 09:04 Richard Ambler

Sí, echa un vistazo al decorador de método estático :

>>> class C:
...     @staticmethod
...     def hello():
...             print "Hello World"
...
>>> C.hello()
Hello World
Paolo Bergantino avatar Apr 09 '2009 21:04 Paolo Bergantino