¿Métodos estáticos en Python?
¿ Puedo definir un método estático al que pueda llamar directamente en la instancia de clase? p.ej,
MyClass.the_static_method()
Sí, usando el staticmethod
decorador:
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 staticmethod
como 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 staticmethod
con 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 (comoC().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.
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 TypeError
para 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)
Sí, echa un vistazo al decorador de método estático :
>>> class C:
... @staticmethod
... def hello():
... print "Hello World"
...
>>> C.hello()
Hello World