Os métodos estáticos em Python?
-
09-09-2019 - |
Pergunta
É possível ter métodos estáticos em Python para que eu possa chamá-los sem inicializar uma classe, como:
ClassName.StaticMethod ( )
Solução
Sim, usando o staticmethod decorador
class MyClass(object):
@staticmethod
def the_static_method(x):
print x
MyClass.the_static_method(2) # outputs 2
Note que algum código pode usar o velho método de definição de um método estático, usando staticmethod
como uma função em vez de um decorador. Isso só deve ser usado se você tem para suportar versões antigas do Python (2.2 e 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
Isto é inteiramente idêntica ao primeiro exemplo (usando @staticmethod
), não apenas usando o bom decorador sintaxe
Finalmente, use staticmethod()
com moderação! Há muito poucas situações onde estáticos-métodos são necessários em Python, e eu os vi usado muitas vezes em uma função separada "top-level" teria sido mais clara.
O seguinte é textualmente a partir da documentação: :
Um método estático não recebe um primeiro argumento implícito. Para declarar um método estático, use esta expressão:
class C: @staticmethod def f(arg1, arg2, ...): ...
A forma @staticmethod é uma função decorador - veja a descrição de definições de funções em As definições de função para mais detalhes.
Ele pode ser chamado quer na classe (como
C.f()
) ou em uma instância (comoC().f()
). A instância é ignorado, exceto para a sua classe.Os métodos estáticos em Python são semelhantes aos encontrados em Java ou C ++. Para um conceito mais avançado, consulte
classmethod()
.Para mais informações sobre métodos estáticos, consulte a documentação sobre a hierarquia de tipo padrão em O tipo de hierarquia padrão .
Novo na versão 2.2.
alterado na versão 2.4:. Função sintaxe decorador adicionado
Outras dicas
Eu acho que Steven é realmente direita. Para responder à pergunta original, em seguida, a fim de estabelecer um método de classe, simplesmente assumir que o primeiro argumento não vai ser uma instância chamando, em seguida, certifique-se que você só chamar o método da classe.
(Note-se que esta resposta refere-se a Python 3.x Em Python 2.x você vai ter um TypeError
para chamar o método na própria classe.)
Por exemplo:
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)
Neste código, o método "Rollcall" assume que o primeiro argumento não é uma instância (como seria se fosse chamado por uma instância em vez de uma classe). Enquanto "Rollcall" é chamado a partir da classe em vez de uma instância, o código irá funcionar bem. Se tentarmos chamar "Rollcall" de uma instância, por exemplo:.
rex.rollCall(-1)
No entanto, ele poderia causar uma exceção a ser levantada porque iria enviar dois argumentos:. Próprio e -1, e "Rollcall" só é definido para aceitar um argumento
Aliás, rex.rollCall () iria enviar o número correto de argumentos, mas também causa uma exceção a ser levantada porque agora n estaria representando uma instância de cão (ou seja, rex), quando os espera função n ser numérica.
Este é o lugar onde a decoração vem em: Se preceder o método "Rollcall" com
@staticmethod
então, prevendo explicitamente que o método é estático, podemos até chamá-lo de uma instância. Agora,
rex.rollCall(-1)
iria funcionar. A inserção de @staticmethod antes de uma definição de método, então, pára uma instância de enviar-se como um argumento.
Você pode verificar isso ao tentar o seguinte código com e sem a linha @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)
Sim, consulte a staticmethod decorador:
>>> class C:
... @staticmethod
... def hello():
... print "Hello World"
...
>>> C.hello()
Hello World
Você realmente não precisa usar o decorador @staticmethod
. Apenas declarando um método (que não espera que o parâmetro self) e chamá-lo a partir da classe. O decorador está lá apenas no caso de você querer ser capaz de chamá-lo de uma instância bem (o que não era o que você queria fazer)
Na maior parte, você só usar funções embora ...
Os métodos estáticos em Python?
É possível ter métodos estáticos em Python para que eu possa chamá-los sem inicializar uma classe, como:
ClassName.StaticMethod()
Sim, métodos estáticos pode ser criado assim (embora seja um pouco mais Pythonic usar sublinhados em vez de CamelCase para métodos):
class ClassName(object):
@staticmethod
def static_method(kwarg1=None):
'''return a value that is a function of kwarg1'''
As utilizações acima a sintaxe decorador. Esta sintaxe é equivalente a
class ClassName(object):
def static_method(kwarg1=None):
'''return a value that is a function of kwarg1'''
static_method = staticmethod(static_method)
Isto pode ser usado apenas como você descreveu:
ClassName.static_method()
Um embutido exemplo de um método estático é str.maketrans()
em Python 3, que era uma função no módulo string
em Python 2.
Outra opção que pode ser usado como você descreve é ??o classmethod
, a diferença é que o classmethod recebe a classe como um primeiro argumento implícito, e se uma subclasse, então fica a subclasse como o primeiro argumento implícito.
class ClassName(object):
@classmethod
def class_method(cls, kwarg1=None):
'''return a value that is a function of the class and kwarg1'''
Note que cls
não é um nome desejado para o primeiro argumento, mas a maioria dos programadores Python experiente irá considerá-la mal feito, se você usar qualquer outra coisa.
Estes são tipicamente usados ??como construtores alternativas.
new_instance = ClassName.class_method()
A builtin exemplo é dict.fromkeys()
:
new_dict = dict.fromkeys(['key1', 'key2'])
Além das particularidades de como método estático objetos se comportam , há é um certo tipo de beleza que você pode atacar com eles quando se trata de organizar seu código de nível de módulo.
# garden.py
def trim(a):
pass
def strip(a):
pass
def bunch(a, b):
pass
def _foo(foo):
pass
class powertools(object):
"""
Provides much regarded gardening power tools.
"""
@staticmethod
def answer_to_the_ultimate_question_of_life_the_universe_and_everything():
return 42
@staticmethod
def random():
return 13
@staticmethod
def promise():
return True
def _bar(baz, quux):
pass
class _Dice(object):
pass
class _6d(_Dice):
pass
class _12d(_Dice):
pass
class _Smarter:
pass
class _MagicalPonies:
pass
class _Samurai:
pass
class Foo(_6d, _Samurai):
pass
class Bar(_12d, _Smarter, _MagicalPonies):
pass
...
# tests.py
import unittest
import garden
class GardenTests(unittest.TestCase):
pass
class PowertoolsTests(unittest.TestCase):
pass
class FooTests(unittest.TestCase):
pass
class BarTests(unittest.TestCase):
pass
...
# interactive.py
from garden import trim, bunch, Foo
f = trim(Foo())
bunch(f, Foo())
...
# my_garden.py
import garden
from garden import powertools
class _Cowboy(garden._Samurai):
def hit():
return powertools.promise() and powertools.random() or 0
class Foo(_Cowboy, garden.Foo):
pass
Agora se torna um pouco mais intuitiva e auto-documentado em que contexto certos componentes são feitos para serem usados ??e panelas para fora idealmente para nomear casos de teste distintas, bem como ter uma abordagem simples de como módulos de teste mapear para módulos de reais sob testes para os puristas.
Eu frequentemente encontrá-lo viável para aplicar esta abordagem para a organização de código utilidade de um projeto. Muitas vezes, as pessoas imediatamente correr e criar um pacote utils
e acabar com 9 módulos, dos quais um tem 120 LOC eo resto são duas dúzias LOC na melhor das hipóteses. Eu prefiro começar com isso e convertê-lo em um pacote e criar módulos apenas para os animais que realmente merecem-los:
# utils.py
class socket(object):
@staticmethod
def check_if_port_available(port):
pass
@staticmethod
def get_free_port(port)
pass
class image(object):
@staticmethod
def to_rgb(image):
pass
@staticmethod
def to_cmyk(image):
pass
Talvez a opção mais simples é apenas para colocar essas funções fora da classe:
class Dog(object):
def __init__(self, name):
self.name = name
def bark(self):
if self.name == "Doggy":
return barking_sound()
else:
return "yip yip"
def barking_sound():
return "woof woof"
Usando este método, as funções que modificam ou utilizam estado objecto interna (ter efeitos colaterais) pode ser mantida na classe, e as funções de utilidade reutilizáveis ??pode ser movido para fora.
Vamos dizer que este arquivo é chamado dogs.py
. Para usá-los, você chamaria dogs.barking_sound()
vez de dogs.Dog.barking_sound
.
Se você realmente precisa de um método estático para ser parte da classe, você pode usar o staticmethod decorador.
Assim, os métodos estáticos são os métodos que podem ser chamados sem criar o objeto de uma classe. Por exemplo: -
@staticmethod
def add(a, b):
return a + b
b = A.add(12,12)
print b
No add
exemplo método acima é chamado pelo A
nome da classe e não o nome do objeto.
métodos Python estáticos podem ser criados de duas maneiras.
-
Usando staticmethod ()
class Arithmetic: def add(x, y): return x + y # create add static method Arithmetic.add = staticmethod(Arithmetic.add) print('Result:', Arithmetic.add(15, 10))
Output:
Resultado: 25
-
Usando @staticmethod
class Arithmetic: # create add static method @staticmethod def add(x, y): return x + y print('Result:', Arithmetic.add(15, 10))
Output:
Resultado: 25
Eu encontro esta pergunta de vez em quando. O caso de uso e exemplo que eu gosto de é:
jeffs@jeffs-desktop:/home/jeffs $ python36
Python 3.6.1 (default, Sep 7 2017, 16:36:03)
[GCC 6.3.0 20170406] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cmath
>>> print(cmath.sqrt(-4))
2j
>>>
>>> dir(cmath)
['__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atanh', 'cos', 'cosh', 'e', 'exp', 'inf', 'infj', 'isclose', 'isfinite', 'isinf', 'isnan', 'log', 'log10', 'nan', 'nanj', 'phase', 'pi', 'polar', 'rect', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau']
>>>
Não faz sentido criar um objeto de cmath classe, porque não há nenhum estado em um objeto cmath. No entanto, cmath é um conjunto de métodos que estão todos relacionados de alguma forma. No meu exemplo acima, todas as funções em ato cmath em números complexos, de alguma forma.