Me encontré con un error de método no vinculado en Python con el código
import random
class Sample(object):
'''This class defines various methods related to the sample'''
def drawSample(samplesize,List):
sample=random.sample(List,samplesize)
return sample
Choices=range(100)
print Sample.drawSample(5,Choices)
Después de leer muchas publicaciones útiles aquí, pensé cómo podría agregar @staticmethod
arriba para que el código funcione. Soy un novato en Python. ¿Alguien puede explicar por qué uno querría definir métodos estáticos? O, ¿por qué no todos los métodos se definen como métodos estáticos?
python
oop
static-methods
Curious2learn
fuente
fuente
Respuestas:
Los métodos estáticos tienen un uso limitado, porque no tienen acceso a los atributos de una instancia de una clase (como lo hace un método regular), y no tienen acceso a los atributos de la clase en sí (como lo hace un método de clase ).
Por lo tanto, no son útiles para los métodos del día a día.
Sin embargo, pueden ser útiles para agrupar alguna función de utilidad junto con una clase, por ejemplo, una simple conversión de un tipo a otro, que no necesita acceso a ninguna información aparte de los parámetros proporcionados (y quizás algunos atributos globales del módulo. )
Pueden colocarse fuera de la clase, pero agruparlos dentro de la clase puede tener sentido donde solo sean aplicables allí.
También puede hacer referencia al método a través de una instancia o la clase, en lugar del nombre del módulo, lo que puede ayudar al lector a comprender con qué instancia está relacionado el método.
fuente
Locale
clase de ejemplo , cuyas instancias serán locales (obvio). UngetAvailableLocales()
método sería un buen ejemplo de un método estático de dicha clase: claramente pertenece a la clase Locale, mientras que tampoco pertenece a ninguna instancia en particular.class_name.attribute
, simplemente nocls.attribute
oself.attribute
. Esto es cierto para los atributos "públicos". Por convención, no debe acceder a los atributos ocultos con un guión bajo, o nombres alterados con dos guiones bajos, de esta manera. También significa que su código será más frágil cuando los atributos cambien de lugar en la jerarquía de herencia.Consulte este artículo para obtener una explicación detallada.
TL; DR
1.Elimina el uso de
self
argumentos.Reduce el uso de memoria porque Python no tiene que crear una instancia de un método enlazado para cada objeto iniciado:
>>>RandomClass().regular_method is RandomClass().regular_method False >>>RandomClass().static_method is RandomClass().static_method True >>>RandomClass.static_method is RandomClass().static_method True
3. Mejora la legibilidad del código, lo que significa que el método no depende del estado del objeto en sí.
Permite la invalidación del método en el sentido de que si el método se definiera a nivel de módulo (es decir, fuera de la clase), una subclase no podría invalidar ese método.
fuente
Esto no es exactamente el punto de su pregunta real, pero como ha dicho que es un novato en Python, tal vez sea útil, y nadie más ha salido y lo ha dicho explícitamente.
Nunca hubiera arreglado el código anterior haciendo del método un método estático. O habría abandonado la clase y solo habría escrito una función:
def drawSample(samplesize,List): sample=random.sample(List,samplesize) return sample Choices=range(100) print drawSample(5,Choices)
Si tiene muchas funciones relacionadas, puede agruparlas en un módulo, es decir, ponerlas todas en el mismo archivo, llamado
sample.py
por ejemplo; entoncesimport sample Choices=range(100) print sample.drawSample(5,Choices)
O habría agregado un
__init__
método a la clase y creado una instancia que tenía métodos útiles:class Sample(object): '''This class defines various methods related to the sample''' def __init__(self, thelist): self.list = thelist def draw_sample(self, samplesize): sample=random.sample(self.list,samplesize) return sample choices=Sample(range(100)) print choices.draw_sample(5)
(También cambié las convenciones de casos en el ejemplo anterior para que coincida con el estilo recomendado por PEP 8.)
Una de las ventajas de Python es que no te obliga a usar clases para todo. Puede usarlos solo cuando hay datos o estados que deberían estar asociados con los métodos, para eso son las clases. De lo contrario, puede usar funciones, que es para lo que están las funciones.
fuente
¿Por qué querría uno definir métodos estáticos ?
Supongamos que tenemos un
class
llamadoMath
entoncesnadie querrá crear el objeto de
class Math
y luego invocar métodos como
ceil
yfloor
yfabs
en él.Entonces los hacemos
static
.Por ejemplo haciendo
>> Math.floor(3.14)
es mucho mejor que
>> mymath = Math() >> mymath.floor(3.14)
Entonces son útiles de alguna manera. No es necesario crear una instancia de una clase para usarlos.
¿Por qué no todos los métodos se definen como métodos estáticos ?
No tienen acceso a variables de instancia.
class Foo(object): def __init__(self): self.bar = 'bar' def too(self): print self.bar @staticmethod def foo(): print self.bar Foo().too() # works Foo.foo() # doesn't work
Es por eso que no hacemos que todos los métodos sean estáticos.
fuente
Math
. Por eso escribí con mayúsculaM
.Math
en primer lugar, no hay ninguna razón para que hayas creado una clase, un módulo encajaría mejor. Intente encontrar un ejemplo de una clase que tenga sentido como clase, no una de la que "nadie querrá crear un objeto" .Cuando llama a un objeto de función desde una instancia de objeto, se convierte en un 'método enlazado' y obtiene que el objeto de instancia en sí se pasa como primer argumento.
Cuando llama a un
classmethod
objeto (que envuelve un objeto de función) en una instancia de objeto, la clase del objeto de instancia se pasa como primer argumento.Cuando llama a un
staticmethod
objeto (que envuelve un objeto de función), no se utiliza un primer argumento implícito.class Foo(object): def bar(*args): print args @classmethod def baaz(*args): print args @staticmethod def quux(*args): print args >>> foo = Foo() >>> Foo.bar(1,2,3) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unbound method bar() must be called with Foo instance as first argument (got int instance instead) >>> Foo.baaz(1,2,3) (<class 'Foo'>, 1, 2, 3) >>> Foo.quux(1,2,3) (1, 2, 3) >>> foo.bar(1,2,3) (<Foo object at 0x1004a4510>, 1, 2, 3) >>> foo.baaz(1,2,3) (<class 'Foo'>, 1, 2, 3) >>> foo.quux(1,2,3) (1, 2, 3)
fuente
Los métodos estáticos son excelentes porque no es necesario declarar una instancia del objeto al que pertenece el método.
El sitio de Python tiene una excelente documentación sobre métodos estáticos aquí:
http://docs.python.org/library/functions.html#staticmethod
fuente
Las alternativas a una
staticmethod
son:classmethod
,instancemethod
yfunction
. Si no sabe cuáles son, desplácese hasta la última sección. Si astaticmethod
es mejor que cualquiera de estas alternativas, depende del propósito con el que esté escrito.ventajas del método estático de Python
staticmethod
es mejor que aclassmethod
oinstancemethod
. De esa manera, está claro (del@staticmethod
decorador) que el estado de la clase y la instancia no se lee ni se modifica. Sin embargo, el uso de afunction
hace que esa distinción sea aún más clara (consulte las desventajas).staticmethod
es la misma que la de aclassmethod
oinstancemethod
, a saber<instance>.<method>(<arguments>)
. Por lo tanto, se puede reemplazar fácilmente por uno de los tres si se necesita más adelante o en una clase derivada. No puedes hacer eso con un simplefunction
.staticmethod
puede usar A en lugar de afunction
para dejar en claro que pertenece subjetivamente a una clase y evitar conflictos de espacio de nombres.desventajas del método estático de Python
staticmethod
es la misma que la de aclassmethod
oinstancemethod
. Esto enmascara el hecho de que elstaticmethod
no lee ni modifica la información del objeto. Esto hace que el código sea más difícil de leer. ¿Por qué no usar simplemente unfunction
?staticmethod
es difícil de reutilizar si alguna vez necesita llamarlo desde fuera de la clase / instancia donde se definió. Si existe alguna posibilidad de reutilización, afunction
es la mejor opción.staticmethod
rara vez se utiliza, por lo que la gente que lee el código que incluye uno puede tomar un poco más de tiempo para leerlo.alternativas a un método estático en Python
Para abordar el tema de las ventajas del
staticmethod
, necesitamos saber cuáles son las alternativas y en qué se diferencian entre sí.staticmethod
pertenece a una clase pero no puede acceder ni modificar ninguna instancia o información de clase.Hay tres alternativas para ello:
classmethod
tiene acceso a la clase de la persona que llama.instancemethod
tiene acceso a la instancia de la persona que llama y su clase.function
tiene nada que ver con las clases. Es el más cercano en capacidad alstaticmethod
.Así es como se ve esto en el código:
# function # has nothing to do with a class def make_cat_noise(asker_name): print('Hi %s, mieets mieets!' % asker_name) # Yey, we can make cat noises before we've even defined what a cat is! make_cat_noise('JOey') # just a function class Cat: number_of_legs = 4 # special instance method __init__ def __init__(self, name): self.name = name # instancemethod # the instance (e.g. Cat('Kitty')) is passed as the first method argument def tell_me_about_this_animal(self, asker_name): print('Hi %s, This cat has %d legs and is called %s' % (asker_name, self.number_of_legs, self.name)) # classmethod # the class (e.g. Cat) is passed as the first method argument # by convention we call that argument cls @classmethod def tell_me_about_cats(cls, asker_name): print("Hi %s, cats have %d legs." % (asker_name, cls.number_of_legs)) # cls.name # AttributeError because only the instance has .name # self.name # NameError because self isn't defined in this namespace # staticmethod # no information about the class or the instance is passed to the method @staticmethod def make_noise(asker_name): print('Hi %s, meooow!' % asker_name) # class and instance are not accessible from here # one more time for fun! make_cat_noise('JOey') # just a function # We just need the class to call a classmethod or staticmethod: Cat.make_noise('JOey') # staticmethod Cat.tell_me_about_cats('JOey') # classmethod # Cat.tell_me_about_this_animal('JOey') # instancemethod -> TypeError # With an instance we can use instancemethod, classmethod or staticmethod mycat = Cat('Kitty') # mycat is an instance of the class Cat mycat.make_noise('JOey') # staticmethod mycat.tell_me_about_cats('JOey') # classmethod mycat.tell_me_about_this_animal('JOey') # instancemethod
fuente
Debido a que las funciones de espacio de nombres son agradables (como se señaló anteriormente):
Cuando quiero ser explícito sobre los métodos que no cambian el estado del objeto, utilizo métodos estáticos. Esto desalienta a las personas de mi equipo a comenzar a cambiar los atributos del objeto en esos métodos.
Cuando refactorizo un código realmente podrido, empiezo por intentar crear tantos métodos
@staticmethod
como sea posible. Esto me permite luego extraer estos métodos en una clase, aunque estoy de acuerdo, esto es algo que rara vez uso, me resultó útil algunas veces.fuente
En mi opinión, no hay un beneficio de rendimiento único al usar
@staticmethod
s en comparación con simplemente definir la función fuera y separada de la clase a la que de otro modo sería una@staticmethod
.Lo único que diría que justifica su existencia es la conveniencia. Los métodos estáticos son comunes en otros lenguajes de programación populares, entonces, ¿por qué no Python? Si desea crear una función con un comportamiento que está muy estrechamente asociado con la clase para la que la está creando, pero en realidad no accede / modifica los datos internos de una instancia de la clase de una manera que justifique su conceptualización como un típico método de esa clase, luego abofetee un
@staticmethod
encima de él y cualquiera que lea su código aprenderá inmediatamente mucho sobre la naturaleza del método y su relación con la clase.Una cosa que a veces me gusta hacer es colocar la funcionalidad que mi clase usa mucho internamente en los
@staticmethod
s privados . De esa manera, no abarrotaré la API expuesta por mi módulo con métodos que nadie que use mi módulo necesitaría ver y mucho menos usar.fuente
Los métodos estáticos casi no tienen razón de ser en Python. Utiliza métodos de instancia o métodos de clase.
def method(self, args): self.member = something @classmethod def method(cls, args): cls.member = something @staticmethod def method(args): MyClass.member = something # The above isn't really working # if you have a subclass
fuente
staticmethod
, o cualquier explicación de lo que es unclassmethod
es o por qué y cómo es "mejor" que los estáticos.staticmethod
en contra en los documentos para respaldar su afirmación de que es cruft o la afirmación de Georg queclassmethod
debería usarse en su lugar).