python - que - ¿Cuál es la diferencia entre @staticmethod y @classmethod?
static method python 3 (23)
¿Cuál es la diferencia entre @staticmethod y @classmethod en Python?
Es posible que haya visto un código Python como este pseudocódigo, que demuestra las firmas de los distintos tipos de métodos y proporciona una cadena de documentos para explicar cada uno:
class Foo(object):
def a_normal_instance_method(self, arg_1, kwarg_2=None):
''''''
Return a value that is a function of the instance with its
attributes, and other arguments such as arg_1 and kwarg2
''''''
@staticmethod
def a_static_method(arg_0):
''''''
Return a value that is a function of arg_0. It does not know the
instance or class it is called from.
''''''
@classmethod
def a_class_method(cls, arg1):
''''''
Return a value that is a function of the class and other arguments.
respects subclassing, it is called with the class it is called from.
''''''
El método de instancia normal
Primero voy a explicar un a_normal_instance_method
. Esto se llama precisamente un " método de instancia ". Cuando se usa un método de instancia, se usa como una función parcial (a diferencia de una función total, definida para todos los valores cuando se ve en el código fuente), es decir, cuando se usa, el primero de los argumentos está predefinido como la instancia de objeto, con todos sus atributos dados. Tiene la instancia del objeto enlazado a ella, y debe llamarse desde una instancia del objeto. Normalmente, accederá a varios atributos de la instancia.
Por ejemplo, esta es una instancia de una cadena:
'', ''
Si usamos el método de instancia, join
en esta cadena, para unirnos a otro iterable, obviamente es una función del ejemplar, además de ser una función de la lista iterable, [''a'', ''b'', ''c'']
:
>>> '', ''.join([''a'', ''b'', ''c''])
''a, b, c''
Métodos de enlace
Los métodos de instancia se pueden enlazar a través de una búsqueda de puntos para su uso posterior.
Por ejemplo, esto une el método str.join
a la instancia '':''
:
>>> join_with_colons = '':''.join
Y luego podemos usar esto como una función que ya tiene el primer argumento vinculado. De esta manera, funciona como una función parcial en la instancia:
>>> join_with_colons(''abcde'')
''a:b:c:d:e''
>>> join_with_colons([''FF'', ''FF'', ''FF'', ''FF'', ''FF'', ''FF''])
''FF:FF:FF:FF:FF:FF''
Método estático
El método estático no toma la instancia como un argumento.
Es muy similar a una función de nivel de módulo.
Sin embargo, una función de nivel de módulo debe residir en el módulo y ser especialmente importada a otros lugares donde se usa.
Sin embargo, si se adjunta al objeto, lo seguirá de manera conveniente a través de la importación y la herencia.
Un ejemplo de un método estático es str.maketrans
, movido desde el módulo de string
en Python 3. Hace que una tabla de traducción sea adecuada para el consumo por str.translate
. Parece bastante tonto cuando se usa desde una instancia de una cadena, como se muestra a continuación, pero importar la función desde el módulo de string
es bastante torpe, y es bueno poder llamarlo desde la clase, como en str.maketrans
# demonstrate same function whether called from instance or not:
>>> '', ''.maketrans(''ABC'', ''abc'')
{65: 97, 66: 98, 67: 99}
>>> str.maketrans(''ABC'', ''abc'')
{65: 97, 66: 98, 67: 99}
En Python 2, tienes que importar esta función desde el módulo de cadena cada vez menos útil:
>>> import string
>>> ''ABCDEFG''.translate(string.maketrans(''ABC'', ''abc''))
''abcDEFG''
Método de clase
Un método de clase es similar a un método de instancia en que toma un primer argumento implícito, pero en lugar de tomar la instancia, toma la clase. Con frecuencia, estos se utilizan como constructores alternativos para un mejor uso semántico y admitirán la herencia.
El ejemplo más canónico de un método de clase incorporado es dict.fromkeys
. Se utiliza como un constructor alternativo de dict, (adecuado para cuando sabe cuáles son sus claves y desea un valor predeterminado para ellas).
>>> dict.fromkeys([''a'', ''b'', ''c''])
{''c'': None, ''b'': None, ''a'': None}
Cuando hacemos una subclase dict, podemos usar el mismo constructor, que crea una instancia de la subclase.
>>> class MyDict(dict): ''A dict subclass, use to demo classmethods''
>>> md = MyDict.fromkeys([''a'', ''b'', ''c''])
>>> md
{''a'': None, ''c'': None, ''b'': None}
>>> type(md)
<class ''__main__.MyDict''>
Consulte el código fuente de pandas para ver otros ejemplos similares de constructores alternativos, y vea también la documentación oficial de Python sobre el classmethod
de classmethod
y el classmethod
staticmethod
.
¿Cuál es la diferencia entre una función decorada con @staticmethod
y una decorada con @classmethod
?
@classmethod: se puede usar para crear un acceso global compartido a todas las instancias creadas de esa clase ... como actualizar un registro por varios usuarios ... Particularmente, encontré que es útil al crear singletons también ... )
Método estático: no tiene nada que ver con la clase o instancia asociada con ... pero para facilitar la lectura puede usar un método estático
Básicamente, @classmethod
un método cuyo primer argumento es la clase a la que se llama (en lugar de la instancia de la clase), @staticmethod
no tiene ningún argumento implícito.
Creo que una mejor pregunta es "¿Cuándo usarías @classmethod vs @staticmethod?"
@classmethod le permite acceder fácilmente a miembros privados asociados a la definición de clase. esta es una gran manera de hacer singletons o clases de fábrica que controlan la cantidad de instancias de los objetos creados.
@staticmethod proporciona ganancias de rendimiento marginales, pero aún no he visto un uso productivo de un método estático dentro de una clase que no se pueda lograr como una función independiente fuera de la clase.
Déjame decirte la similitud entre un método decorado con @classmethod vs @staticmethod primero.
Similitud: se puede invocar a ambos en la propia Clase , en lugar de solo en la instancia de la clase. Entonces, ambos en cierto sentido son métodos de la clase .
Diferencia: un método de clase recibirá la clase como el primer argumento, mientras que un método estático no.
Por lo tanto, un método estático, en cierto sentido, no está vinculado a la Clase en sí y simplemente se queda ahí porque puede tener una funcionalidad relacionada.
>>> class Klaus:
@classmethod
def classmthd(*args):
return args
@staticmethod
def staticmthd(*args):
return args
# 1. Call classmethod without any arg
>>> Klaus.classmthd()
(__main__.Klaus,) # the class gets passed as the first argument
# 2. Call classmethod with 1 arg
>>> Klaus.classmthd(''chumma'')
(__main__.Klaus, ''chumma'')
# 3. Call staticmethod without any arg
>>> Klaus.staticmthd()
()
# 4. Call staticmethod with 1 arg
>>> Klaus.staticmthd(''chumma'')
(''chumma'',)
Empecé a aprender el lenguaje de programación con C ++ y luego con Java y luego con Python, por lo que esta pregunta también me molestó mucho, hasta que entendí el uso simple de cada uno.
Método de clase: a diferencia de Python, Java y C ++ no tienen sobrecarga de constructores. Y así, para lograr esto, podrías usar el classmethod
. El siguiente ejemplo explicará esto
Consideremos que tenemos una clase Person
que toma dos argumentos first_name
y last_name
y crea la instancia de Person.
class Person(object):
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
Ahora, si el requisito llega donde necesita crear una clase con un solo nombre, solo un primer nombre, no puede hacer algo como esto en python.
Esto le dará un error cuando intentará crear un objeto (instancia).
class Person(object):
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
def __init__(self, first_name):
self.first_name = first_name
Sin embargo, podría lograr lo mismo usando @classmethod
como se menciona a continuación
class Person(object):
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
@classmethod
def get_person(cls, first_name):
return cls(first_name, "")
Método estático :: Esto es bastante simple, no está vinculado a una instancia o clase y simplemente puede llamarlo usando el nombre de clase.
Entonces, digamos que en el ejemplo anterior necesita una validación de que el primer nombre no debe exceder los 20 caracteres, simplemente puede hacer esto.
@staticmethod
def validate_name(name):
return len(name) <= 20
y simplemente puedes llamar usando el nombre de clase
Person.validate_name("Gaurang Shah")
Mi contribución demuestra la diferencia entre los @classmethod
, @staticmethod
y instance, incluida la forma en que una instancia puede llamar indirectamente a @staticmethod
. Pero en lugar de llamar indirectamente a @staticmethod
desde una instancia, hacerla privada puede ser más "pythonic". Obtener algo de un método privado no se demuestra aquí, pero es básicamente el mismo concepto.
#!python3
from os import system
system(''cls'')
# % % % % % % % % % % % % % % % % % % % %
class DemoClass(object):
# instance methods need a class instance and
# can access the instance through ''self''
def instance_method_1(self):
return ''called from inside the instance_method_1()''
def instance_method_2(self):
# an instance outside the class indirectly calls the static_method
return self.static_method() + '' via instance_method_2()''
# class methods don''t need a class instance, they can''t access the
# instance (self) but they have access to the class itself via ''cls''
@classmethod
def class_method(cls):
return ''called from inside the class_method()''
# static methods don''t have access to ''cls'' or ''self'', they work like
# regular functions but belong to the class'' namespace
@staticmethod
def static_method():
return ''called from inside the static_method()''
# % % % % % % % % % % % % % % % % % % % %
# works even if the class hasn''t been instantiated
print(DemoClass.class_method() + ''/n'')
'''''' called from inside the class_method() ''''''
# works even if the class hasn''t been instantiated
print(DemoClass.static_method() + ''/n'')
'''''' called from inside the static_method() ''''''
# % % % % % % % % % % % % % % % % % % % %
# >>>>> all methods types can be called on a class instance <<<<<
# instantiate the class
democlassObj = DemoClass()
# call instance_method_1()
print(democlassObj.instance_method_1() + ''/n'')
'''''' called from inside the instance_method_1() ''''''
# # indirectly call static_method through instance_method_2(), there''s really no use
# for this since a @staticmethod can be called whether the class has been
# instantiated or not
print(democlassObj.instance_method_2() + ''/n'')
'''''' called from inside the static_method() via instance_method_2() ''''''
# call class_method()
print(democlassObj.class_method() + ''/n'')
'''''' called from inside the class_method() ''''''
# call static_method()
print(democlassObj.static_method())
'''''' called from inside the static_method() ''''''
"""
# whether the class is instantiated or not, this doesn''t work
print(DemoClass.instance_method_1() + ''/n'')
''''''
TypeError: TypeError: unbound method instancemethod() must be called with
DemoClass instance as first argument (got nothing instead)
''''''
"""
Otra consideración con respecto a staticmethod vs classmethod viene con herencia. Digamos que tienes la siguiente clase:
class Foo(object):
@staticmethod
def bar():
return "In Foo"
Y luego desea anular la bar()
en una clase secundaria:
class Foo2(Foo):
@staticmethod
def bar():
return "In Foo2"
Esto funciona, pero tenga en cuenta que ahora la implementación de la bar()
en la clase secundaria ( Foo2
) ya no puede aprovechar nada específico de esa clase. Por ejemplo, digamos que Foo2
tenía un método llamado magic()
que desea usar en la implementación de Foo2
de bar()
:
class Foo2(Foo):
@staticmethod
def bar():
return "In Foo2"
@staticmethod
def magic():
return "Something useful you''d like to use in bar, but now can''t"
La solución aquí sería llamar a Foo2.magic()
en la bar()
, pero luego te estás repitiendo (si el nombre de Foo2
cambia, deberás recordar actualizar el método de la bar()
).
Para mí, esto es una leve violación del principio de apertura / cierre , ya que una decisión tomada en Foo
está afectando su capacidad para refactorizar el código común en una clase derivada (es decir, está menos abierta a la extensión). Si bar()
fuera un classmethod
estaríamos bien:
class Foo(object):
@classmethod
def bar(cls):
return "In Foo"
class Foo2(Foo):
@classmethod
def bar(cls):
return "In Foo2 " + cls.magic()
@classmethod
def magic(cls):
return "MAGIC"
print Foo2().bar()
Da: In Foo2 MAGIC
Para decidir si usar @staticmethod o @classmethod tiene que buscar dentro de su método. Si su método accede a otras variables / métodos en su clase, entonces use @classmethod . Por otro lado, si su método no toca ninguna otra parte de la clase, use @staticmethod.
class Apple:
_counter = 0
@staticmethod
def about_apple():
print(''Apple is good for you.'')
# note you can still access other member of the class
# but you have to use the class instance
# which is not very nice, because you have repeat yourself
#
# For example:
# @staticmethod
# print(''Number of apples have been juiced: %s'' % Apple._counter)
#
# @classmethod
# print(''Number of apples have been juiced: %s'' % cls._counter)
#
# @classmethod is especially useful when you move your function to other class,
# you don''t have to rename the class reference
@classmethod
def make_apple_juice(cls, number_of_apples):
print(''Make juice:'')
for i in range(number_of_apples):
cls._juice_this(i)
@classmethod
def _juice_this(cls, apple):
print(''Juicing %d...'' % apple)
cls._counter += 1
Quizás un poco de código de ejemplo ayude: note la diferencia en las firmas de llamadas de foo
, class_foo
y static_foo
:
class A(object):
def foo(self,x):
print "executing foo(%s,%s)"%(self,x)
@classmethod
def class_foo(cls,x):
print "executing class_foo(%s,%s)"%(cls,x)
@staticmethod
def static_foo(x):
print "executing static_foo(%s)"%x
a=A()
A continuación se muestra la forma habitual en que una instancia de objeto llama a un método. La instancia de objeto, a
, se pasa implícitamente como primer argumento.
a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>,1)
Con classmethods , la clase de la instancia de objeto se pasa implícitamente como primer argumento en lugar de self
.
a.class_foo(1)
# executing class_foo(<class ''__main__.A''>,1)
También puedes llamar a class_foo
usando la clase. De hecho, si define que algo es un método de clase, probablemente se deba a que tiene la intención de llamarlo desde la clase en lugar de hacerlo desde una instancia de clase. A.foo(1)
habría generado un TypeError, pero A.class_foo(1)
funciona bien:
A.class_foo(1)
# executing class_foo(<class ''__main__.A''>,1)
Un uso que la gente ha encontrado para los métodos de clase es crear constructores alternativos heredables .
Con staticmethods , ni self
(la instancia del objeto) ni cls
(la clase) se pasan implícitamente como primer argumento. Se comportan como funciones simples, excepto que puede llamarlas desde una instancia o la clase:
a.static_foo(1)
# executing static_foo(1)
A.static_foo(''hi'')
# executing static_foo(hi)
Los métodos estáticos se utilizan para agrupar funciones que tienen alguna conexión lógica con una clase a la clase.
foo
es solo una función, pero cuando llama a.foo
no solo obtiene la función, obtiene una versión "parcialmente aplicada" de la función con la instancia del objeto unida como el primer argumento de la función. foo
espera 2 argumentos, mientras que a.foo
solo espera 1 argumento.
a
está obligado a foo
. Eso es lo que se entiende por el término "unido" a continuación:
print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>
Con a.class_foo
, a
no está vinculado a class_foo
, sino que la clase A
está vinculada a class_foo
.
print(a.class_foo)
# <bound method type.class_foo of <class ''__main__.A''>>
Aquí, con un método estático, aunque es un método, a.static_foo
simplemente devuelve una buena función ''ole'' sin argumentos vinculados. static_foo
espera 1 argumento, y a.static_foo
espera 1 argumento también.
print(a.static_foo)
# <function static_foo at 0xb7d479cc>
Y, por supuesto, lo mismo ocurre cuando se llama static_foo
con la clase A
lugar.
print(A.static_foo)
# <function static_foo at 0xb7d479cc>
Se agregaron @decorators en python 2.4 Si está usando python <2.4, puede usar la función classmethod () y staticmethod ().
Por ejemplo, si desea crear un método de fábrica (una función que devuelve una instancia de una implementación diferente de una clase según el argumento que obtenga), puede hacer algo como:
class Cluster(object):
def _is_cluster_for(cls, name):
"""
see if this class is the cluster with this name
this is a classmethod
"""
return cls.__name__ == name
_is_cluster_for = classmethod(_is_cluster_for)
#static method
def getCluster(name):
"""
static factory method, should be in Cluster class
returns a cluster object for the given name
"""
for cls in Cluster.__subclasses__():
if cls._is_cluster_for(name):
return cls()
getCluster = staticmethod(getCluster)
También tenga en cuenta que este es un buen ejemplo para usar un método de clase y un método estático. El método estático pertenece claramente a la clase, ya que usa la clase Clúster internamente. El método de clase solo necesita información sobre la clase y no una instancia del objeto.
Otra ventaja de convertir el método _is_cluster_for
un método de clase es que una subclase puede decidir cambiar su implementación, tal vez porque es bastante genérico y puede manejar más de un tipo de grupo, por lo que no basta con verificar el nombre de la clase.
Trataré de explicar la diferencia básica usando un ejemplo.
class A(object):
x = 0
def say_hi(self):
pass
@staticmethod
def say_hi_static():
pass
@classmethod
def say_hi_class(cls):
pass
def run_self(self):
self.x += 1
print self.x # outputs 1
self.say_hi()
self.say_hi_static()
self.say_hi_class()
@staticmethod
def run_static():
print A.x # outputs 0
# A.say_hi() # wrong
A.say_hi_static()
A.say_hi_class()
@classmethod
def run_class(cls):
print cls.x # outputs 0
# cls.say_hi() # wrong
cls.say_hi_static()
cls.say_hi_class()
1 - podemos llamar directamente static y classmethods sin inicializar
# A.run_self() # wrong
A.run_static()
A.run_class()
2- El método estático no puede llamarse método propio, pero puede llamar a otro método estático y de clase
3- El método estático pertenece a la clase y no usará el objeto en absoluto.
4- El método de clase no está vinculado a un objeto sino a una clase.
Un método estático es un método que no sabe nada sobre la clase o la instancia a la que se llamó. Simplemente obtiene los argumentos que se pasaron, ningún primer argumento implícito. Básicamente es inútil en Python, solo puede usar una función de módulo en lugar de un método estático.
Un método de clase , por otro lado, es un método que pasa la clase a la que fue llamado, o la clase de la instancia en la que fue llamado, como primer argumento. Esto es útil cuando desea que el método sea una fábrica para la clase: dado que obtiene la clase real a la que fue llamado como primer argumento, siempre puede crear una instancia de la clase correcta, incluso cuando hay subclases involucradas. Observe, por ejemplo, cómo dict.fromkeys()
, un método de clase, devuelve una instancia de la subclase cuando se le llama en una subclase:
>>> class DictSubclass(dict):
... def __repr__(self):
... return "DictSubclass"
...
>>> dict.fromkeys("abc")
{''a'': None, ''c'': None, ''b'': None}
>>> DictSubclass.fromkeys("abc")
DictSubclass
>>>
Here hay un breve artículo sobre esta pregunta.
La 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.
La función @classmethod también se puede llamar sin crear una instancia de la clase, pero su definición sigue a la clase Sub, no a la clase Parent, a través de la herencia. Esto se debe a que el primer argumento para la función @classmethod siempre debe ser cls (clase).
La guía definitiva sobre cómo usar métodos estáticos, de clase o abstractos en Python es un buen enlace para este tema y lo resume a continuación.
@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 y 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 (clase).
- 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.
@staticmethod
simplemente deshabilita la función predeterminada como descriptor de método. classmethod envuelve su función en un contenedor invocable que pasa una referencia a la clase propietaria como primer argumento:
>>> class C(object):
... pass
...
>>> def f():
... pass
...
>>> staticmethod(f).__get__(None, C)
<function f at 0x5c1cf0>
>>> classmethod(f).__get__(None, C)
<bound method type.f of <class ''__main__.C''>>
De hecho, classmethod
tiene una sobrecarga de tiempo de ejecución, pero permite acceder a la clase propietaria. Alternativamente, recomiendo usar una metaclase y poner los métodos de clase en esa metaclase:
>>> class CMeta(type):
... def foo(cls):
... print cls
...
>>> class C(object):
... __metaclass__ = CMeta
...
>>> C.foo()
<class ''__main__.C''>
Documentos oficiales de python:
Un método de clase recibe la clase como primer argumento implícito, al igual que un método de instancia recibe la instancia. Para declarar un método de clase, use este idioma:
class C: @classmethod def f(cls, arg1, arg2, ...): ...
La forma
@classmethod
es un decorator funciones; consulte la descripción de las definiciones de funciones en las definiciones de funciones para obtener más información.Se puede llamar en la clase (como
Cf()
) o en una instancia (comoC().f()
). La instancia se ignora a excepción de su clase. Si se llama a un método de clase para una clase derivada, el objeto de clase derivada se pasa como el primer argumento implícito.Los métodos de clase son diferentes a los métodos estáticos C ++ o Java. Si desea esos, vea
staticmethod()
en esta sección.
Un método estático no recibe un primer argumento implícito. Para declarar un método estático, use este idioma:
class C: @staticmethod def f(arg1, arg2, ...): ...
La forma
@staticmethod
es un decorator funciones; consulte la descripción de las definiciones de funciones en las definiciones de funciones para obtener más información.Se puede llamar en la clase (como
Cf()
) o en una instancia (comoC().f()
). La instancia se ignora a excepción de 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, vea
classmethod()
en esta sección.
Métodos estáticos:
- Funciones simples sin auto argumento.
- Trabajar en los atributos de clase; no en los atributos de instancia.
- Puede ser llamado a través de la clase y la instancia.
- La función integrada staticmethod () se utiliza para crearlos.
Beneficios de los métodos estáticos:
- Localiza el nombre de la función en el classscope.
- Mueve el código de función más cerca de donde se usa
Más conveniente para importar en comparación con las funciones a nivel de módulo, ya que cada método no tiene que ser especialmente importado
@staticmethod def some_static_method(*args, **kwds): pass
Métodos de clase:
- Funciones que tienen primer argumento como nombre de clase.
- Puede ser llamado a través de la clase y la instancia.
Estos se crean con la función incorporada classmethod.
@classmethod def some_class_method(cls, *args, **kwds): pass
método de clase vs método estático en Python
Método de clase
El decorador @classmethod, es un decorador de función incorporada que es una expresión que se evalúa después de definir su función. El resultado de esa evaluación oscurece la definición de su función.
Un método de clase recibe la clase como primer argumento implícito, al igual que un método de instancia recibe la instancia
Sintaxis:
class C(object):
@classmethod
def fun(cls, arg1, arg2, ...):
....
fun: function that needs to be converted into a class method
returns: a class method for function.
- Un método de clase es un método que está vinculado a la clase y no al objeto de la clase.
- Tienen acceso al estado de la clase, ya que toma un parámetro de clase que apunta a la clase y no a la instancia del objeto.
- Puede modificar un estado de clase que se aplicaría en todas las instancias de la clase. Por ejemplo, puede modificar una variable de clase que será aplicable a todas las instancias.
Método estático
Un método estático no recibe un primer argumento implícito.
Sintaxis:
class C(object):
@staticmethod
def fun(arg1, arg2, ...):
...
returns: a static method for function fun.
- Un método estático también es un método que está vinculado a la clase y no al objeto de la clase.
- Un método estático no puede acceder o modificar el estado de la clase.
- Está presente en una clase porque tiene sentido que el método esté presente en la clase.
Método de clase vs Método estático
- Un método de clase toma cls como primer parámetro, mientras que un método estático no necesita parámetros específicos.
- Un método de clase puede acceder o modificar el estado de la clase, mientras que un método estático no puede acceder o modificarlo.
- Utilizamos @classmethod decorator en python para crear un método de clase y usamos @staticmethod decorator para crear un método estático en python.
¿Cuándo usar qué?
- Generalmente usamos el método de clase para crear métodos de fábrica. Los métodos de fábrica devuelven el objeto de clase (similar a un constructor) para diferentes casos de uso.
- Generalmente usamos métodos estáticos para crear funciones de utilidad.
¿Cómo definir un método de clase y un método estático?
Para definir un método de clase en python, usamos el decorador @classmethod y para definir un método estático usamos el decorador @staticmethod.
Veamos un ejemplo para entender la diferencia entre ambos. Digamos que queremos crear una persona de clase. Ahora, Python no admite la sobrecarga de métodos como C ++ o Java, por lo que usamos métodos de clase para crear métodos de fábrica. En el siguiente ejemplo, usamos un método de clase para crear un objeto de persona desde el año de nacimiento.
Como se explicó anteriormente, utilizamos métodos estáticos para crear funciones de utilidad. En el siguiente ejemplo, usamos un método estático para verificar si una persona es adulta o no.
Implementación
# Python program to demonstrate
# use of class method and static method.
from datetime import date
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# a class method to create a Person object by birth year.
@classmethod
def fromBirthYear(cls, name, year):
return cls(name, date.today().year - year)
# a static method to check if a Person is adult or not.
@staticmethod
def isAdult(age):
return age > 18
person1 = Person(''mayank'', 21)
person2 = Person.fromBirthYear(''mayank'', 1996)
print person1.age
print person2.age
# print the result
print Person.isAdult(22)
Salida
21
21
True
Analice @staticmethod literalmente proporcionando diferentes perspectivas.
Un método normal de una clase es un método dinámico implícito que toma la instancia como primer argumento.
En contraste, un método estático no toma la instancia como primer argumento, por lo que se llama ''estático'' .
Un método estático es, de hecho, una función tan normal como las que están fuera de una definición de clase.
Afortunadamente, está agrupado en la clase solo para estar más cerca de donde se aplica, o puede desplazarse para encontrarlo.
Los métodos de clase, como su nombre indica, se utilizan para realizar cambios en las clases y no en los objetos. Para realizar cambios en las clases, modificarán los atributos de la clase (no los atributos del objeto), ya que así es como se actualizan las clases. Esta es la razón por la que los métodos de clase toman la clase (convencionalmente denotada por ''cls'') como el primer argumento.
class A(object):
m=54
@classmethod
def class_method(cls):
print "m is %d" % cls.m
Los métodos estáticos, por otro lado, se utilizan para realizar funcionalidades que no están vinculadas a la clase, es decir, no leerán ni escribirán variables de clase. Por lo tanto, los métodos estáticos no toman clases como argumentos. Se utilizan para que las clases puedan realizar funcionalidades que no están directamente relacionadas con el propósito de la clase.
class X(object):
m=54 #will not be referenced
@staticmethod
def static_method():
print "Referencing/calling a variable or function outside this class. E.g. Some global variable/function."
Un rápido pirateo de otros métodos idénticos en iPython revela que @staticmethod
produce ganancias de rendimiento marginales (en los nanosegundos), pero de lo contrario no parece tener ninguna función. Además, cualquier aumento de rendimiento probablemente se eliminará por el trabajo adicional de procesar el método staticmethod()
durante la compilación (lo que ocurre antes de cualquier ejecución de código cuando ejecuta un script).
Por el bien de la legibilidad del código, evitaría a @staticmethod
menos que su método se use para un montón de trabajo, donde los nanosegundos cuentan.
#!/usr/bin/python
#coding:utf-8
class Demo(object):
def __init__(self,x):
self.x = x
@classmethod
def addone(self, x):
return x+1
@staticmethod
def addtwo(x):
return x+2
def addthree(self, x):
return x+3
def main():
print Demo.addone(2)
print Demo.addtwo(2)
#print Demo.addthree(2) #Error
demo = Demo(2)
print demo.addthree(2)
if __name__ == ''__main__'':
main()