Encontrei um erro de método desvinculado em python com o 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)
Depois de ler muitos posts úteis aqui, descobri como poderia adicionar @staticmethod
acima para fazer o código funcionar. Eu sou um novato em python. Alguém pode explicar por que se deseja definir métodos estáticos? Ou, por que nem todos os métodos são definidos como métodos estáticos?
python
oop
static-methods
Curious2learn
fonte
fonte
Respostas:
Os métodos estáticos têm uso limitado, porque eles não têm acesso aos atributos de uma instância de uma classe (como um método regular), e eles não têm acesso aos atributos da própria classe (como um método de classe tem )
Portanto, eles não são úteis para os métodos do dia-a-dia.
No entanto, eles podem ser úteis para agrupar alguma função de utilidade junto com uma classe - por exemplo, uma conversão simples de um tipo para outro - que não precisa de acesso a nenhuma informação além dos parâmetros fornecidos (e talvez alguns atributos globais para o módulo. )
Eles podem ser colocados fora da classe, mas agrupá-los dentro da classe pode fazer sentido onde eles só são aplicáveis lá.
Você também pode fazer referência ao método por meio de uma instância ou classe, em vez do nome do módulo, o que pode ajudar o leitor a entender a que instância o método está relacionado.
fonte
Locale
classe de exemplo , cujas instâncias serão locales (duh). UmgetAvailableLocales()
método seria um bom exemplo de um método estático de tal classe: ele claramente pertence à classe Locale, enquanto também claramente não pertence a nenhuma instância em particular.class_name.attribute
, apenas nãocls.attribute
ouself.attribute
. Isso é verdadeiro para atributos "públicos". Por convenção, você não deve acessar atributos ocultos com um sublinhado ou nomes mutilados com dois sublinhados, dessa forma. Isso também significa que seu código ficará mais frágil quando os atributos mudarem de lugar na hierarquia de herança.Consulte este artigo para obter uma explicação detalhada.
TL; DR
1. Elimina o uso de
self
argumento.2. Reduz o uso de memória porque o Python não precisa instanciar um método vinculado para cada objeto instanciado:
>>>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. Melhora a legibilidade do código, significando que o método não depende do estado do próprio objeto.
4. Permite a sobrescrita de método, pois se o método fosse definido no nível do módulo (ou seja, fora da classe), uma subclasse não seria capaz de sobrescrever esse método.
fonte
Isso não vai exatamente ao ponto da sua pergunta real, mas como você disse que é um novato em Python, talvez seja útil, e ninguém mais apareceu e disse isso explicitamente.
Eu nunca teria corrigido o código acima tornando o método um método estático. Eu teria abandonado a aula e apenas escrito uma função:
def drawSample(samplesize,List): sample=random.sample(List,samplesize) return sample Choices=range(100) print drawSample(5,Choices)
Se você tiver muitas funções relacionadas, pode agrupá-las em um módulo - ou seja, colocá-las todas no mesmo arquivo, com nome,
sample.py
por exemplo; entãoimport sample Choices=range(100) print sample.drawSample(5,Choices)
Ou eu teria adicionado um
__init__
método à classe e criado uma instância com métodos úteis: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)
(Eu também alterei as convenções de caso no exemplo acima para corresponder ao estilo recomendado pelo PEP 8.)
Uma das vantagens do Python é que ele não o força a usar classes para tudo. Você pode usá-los somente quando houver dados ou estado que devem ser associados aos métodos, que é para que servem as classes. Caso contrário, você pode usar funções, para que servem as funções.
fonte
Por que alguém iria querer definir métodos estáticos ?
Suponha que temos um
class
chamadoMath
entãoninguém vai querer criar um objeto de
class Math
e então invocar métodos como
ceil
efloor
efabs
sobre ele.Então, nós os fazemos
static
.Por exemplo fazendo
>> Math.floor(3.14)
é muito melhor que
>> mymath = Math() >> mymath.floor(3.14)
Portanto, eles são úteis de alguma forma. Você não precisa criar uma instância de uma classe para usá-los.
Por que nem todos os métodos são definidos como métodos estáticos ?
Eles não têm acesso a variáveis de instância.
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
É por isso que não tornamos todos os métodos estáticos.
fonte
Math
. É por isso que capitalizeiM
.Math
ser uma classe em primeiro lugar, um módulo seria mais adequado. Tente encontrar um exemplo de uma classe que faça sentido como uma classe, não uma que "ninguém queira criar um objeto" .Quando você chama um objeto de função de uma instância de objeto, ele se torna um 'método vinculado' e obtém o próprio objeto de instância que é passado como primeiro argumento.
Quando você chama um
classmethod
objeto (que envolve um objeto de função) em uma instância de objeto, a classe do objeto de instância é passada como um primeiro argumento.Quando você chama um
staticmethod
objeto (que envolve um objeto de função), nenhum primeiro argumento implícito é usado.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)
fonte
As alternativas para um
staticmethod
são:classmethod
,instancemethod
, efunction
. Se você não sabe o que são, role para baixo até a última seção. Se astaticmethod
for melhor do que qualquer uma dessas alternativas, depende de para que propósito foi escrito.vantagens do método estático Python
staticmethod
é melhor do que aclassmethod
ouinstancemethod
. Dessa forma, fica claro (do@staticmethod
decorador) que o estado da classe e da instância não é lido ou modificado. No entanto, o uso de umfunction
torna essa distinção ainda mais clara (veja as desvantagens).staticmethod
é igual à de aclassmethod
ouinstancemethod
, a saber<instance>.<method>(<arguments>)
. Portanto, ele pode ser facilmente substituído por um dos três, se for necessário posteriormente ou em uma classe derivada. Você não pode fazer isso com um simplesfunction
.staticmethod
pode ser usado em vez de afunction
para deixar claro que subjetivamente pertence a uma classe e para evitar conflitos de espaço de nomes.desvantagens do método estático Python
staticmethod
é igual à de aclassmethod
ouinstancemethod
. Isso mascara o fato de questaticmethod
não lê nem modifica nenhuma informação do objeto. Isso torna o código mais difícil de ler. Por que não usar apenas umfunction
?staticmethod
é difícil de reutilizar se você precisar chamá-lo de fora da classe / instância onde foi definido. Se houver possibilidade de reutilização, afunction
é a melhor escolha.staticmethod
é raramente usado, então as pessoas que lêem um código que o inclui podem demorar um pouco mais para lê-lo.alternativas para um método estático em Python
Para discutir as vantagens do
staticmethod
, precisamos saber quais são as alternativas e como elas diferem umas das outras.staticmethod
pertence a uma classe, mas não pode acessar ou modificar nenhuma instância ou informação de classe.Existem três alternativas para isso:
classmethod
tem acesso à classe do chamador.instancemethod
tem acesso à instância do chamador e sua classe.function
tem nada a ver com aulas. É o mais próximo em capacidade dostaticmethod
.Veja como isso se parece no 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
fonte
os métodos estáticos são ótimos porque você não precisa declarar uma instância do objeto ao qual o método pertence.
O site de python possui uma excelente documentação sobre métodos estáticos aqui:
http://docs.python.org/library/functions.html#staticmethod
fonte
Os métodos estáticos quase não têm razão de ser no Python. Você pode usar métodos de instância ou métodos de classe.
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
fonte
staticmethod
ou nenhuma explicação do queclassmethod
é, por que e como é "melhor" do que os estáticos.staticmethod
nos documentos para apoiar sua alegação de que é cruft, ou a alegação de Georg queclassmethod
deveria ser usada no lugar)Como as funções de namespacing são boas (como foi apontado anteriormente):
Quando quero ser explícito sobre métodos que não alteram o estado do objeto, uso métodos estáticos. Isso desencoraja as pessoas da minha equipe a começar a alterar os atributos do objeto nesses métodos.
Quando eu refatoro um código realmente podre, começo tentando fazer o máximo de métodos
@staticmethod
possível. Isso me permite extrair esses métodos em uma classe - embora eu concorde, isso raramente é algo que eu uso, mas foi útil algumas vezes.fonte
Em minha estimativa, não há um único benefício de desempenho em usar
@staticmethod
s em comparação com apenas definir a função fora e separada da classe que, de outra forma, seria uma@staticmethod
.A única coisa que eu diria que justifica sua existência é a conveniência. Métodos estáticos são comuns em outras linguagens de programação populares, então por que não python? Se você deseja criar uma função com comportamento que está intimamente associado à classe para a qual está criando, mas ela não acessa / modifica os dados internos de uma instância da classe de uma forma que justifique conceituá-la como uma dessa classe, em seguida, coloque um
@staticmethod
acima dele e qualquer pessoa que ler seu código aprenderá imediatamente muito sobre a natureza do método e sua relação com a classe.Uma coisa que gosto de fazer ocasionalmente é colocar funcionalidades que minha classe usa muito internamente em programas privados
@staticmethod
. Dessa forma, eu não entulho a API exposta por meu módulo com métodos que ninguém usando meu módulo precisaria ver, muito menos usar.fonte