É possível ter métodos estáticos em Python que eu poderia chamar sem inicializar uma classe, como:
ClassName.static_method()
É possível ter métodos estáticos em Python que eu poderia chamar sem inicializar uma classe, como:
ClassName.static_method()
Respostas:
Sim, usando o decorador staticmethod
class MyClass(object):
@staticmethod
def the_static_method(x):
print(x)
MyClass.the_static_method(2) # outputs 2
Observe que algum código pode usar o método antigo de definir um método estático, usando staticmethod
como uma função e não como um decorador. Isso só deve ser usado se você tiver que 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
Isso é totalmente idêntico ao primeiro exemplo (usando @staticmethod
), mas não usando a sintaxe agradável do decorador
Finalmente, use staticmethod()
com moderação! Existem muito poucas situações em que métodos estáticos são necessários no Python, e eu os vi usados muitas vezes em que uma função separada de "nível superior" seria mais clara.
A seguir, é apresentado literalmente na documentação :
Um método estático não recebe um primeiro argumento implícito. Para declarar um método estático, use este idioma:
class C: @staticmethod def f(arg1, arg2, ...): ...
O formulário @staticmethod é um decorador de funções - consulte a descrição das definições de funções em Definições de funções para obter detalhes.
Pode ser chamado na classe (como
C.f()
) ou em uma instância (comoC().f()
). A instância é ignorada, exceto por sua classe.Os métodos estáticos no Python são semelhantes aos encontrados em Java ou C ++. Para um conceito mais avançado, consulte
classmethod()
.Para obter mais informações sobre métodos estáticos, consulte a documentação sobre a hierarquia de tipos padrão em A hierarquia de tipos padrão .
Novo na versão 2.2.
Alterado na versão 2.4: Sintaxe do decorador de funções adicionada.
ClassName.methodName()
se fosse um método estático e, em seguida, nenhum self
será fornecido ao método. Como você disse, ainda será possível também chamar esse método como ClassInstance.methodName()
e self
será fornecido como o primeiro parâmetro, independentemente do nome.
Eu acho que Steven está realmente certo . Para responder à pergunta original, então, para configurar um método de classe, simplesmente assuma que o primeiro argumento não será uma instância de chamada e, em seguida, certifique-se de chamar o método apenas da classe.
(Observe que esta resposta se refere ao Python 3.x. No Python 2.x, você receberá um TypeError
por 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)
Nesse 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 e não por uma classe). Desde que "rollCall" seja chamado da classe e não de uma instância, o código funcionará bem. Se tentarmos chamar "rollCall" de uma instância, por exemplo:
rex.rollCall(-1)
no entanto, faria com que uma exceção fosse lançada porque enviaria dois argumentos: ele próprio e -1, e "rollCall" é definido apenas para aceitar um argumento.
Aliás, rex.rollCall () enviaria o número correto de argumentos, mas também causaria uma exceção, porque agora n representaria uma instância Dog (ou seja, rex) quando a função espera que n seja numérico.
É aqui que entra a decoração: se precedermos o método "rollCall" com
@staticmethod
então, declarando explicitamente que o método é estático, podemos chamá-lo de uma instância. Agora,
rex.rollCall(-1)
podia funcionar. A inserção de @staticmethod antes de uma definição de método impede que uma instância se envie como argumento.
Você pode verificar isso tentando 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)
TypeError: unbound method rollCall() must be called with Dog instance as first argument (got int instance instead)
T.my_static_method()
ou type(my_t_instance).my_static_method()
, pois isso é mais claro e torna imediatamente óbvio que estou chamando um método estático.
Sim, confira o decorador staticmethod :
>>> class C:
... @staticmethod
... def hello():
... print "Hello World"
...
>>> C.hello()
Hello World
Você realmente não precisa usar o @staticmethod
decorador. Apenas declarando um método (que não espera o parâmetro self) e chamá-lo da classe O decorador está lá apenas no caso de você querer chamá-lo também de uma instância (que não era o que você queria fazer)
Principalmente, você apenas usa funções ...
class Dummy: def static1(): print "hello from static1" @staticmethod def static2(): print "hello from static2" Dummy.static2() Dummy.static1()
Saída: hello from static2 Traceback <última chamada mais recente>: Arquivo "ll.py", linha 46, em <module> Dummy.static1 () TypeError: o método não estático static1 () deve ser chamado com instância manequim como primeiro argumento (não tem nada em seu lugar)
self
como o primeiro argumento, a menos que você o diga. (ver: decorador)
self
ref de forma apropriada, dependendo de como é chamado. Caso de teste: pastebin.com/12DDV7DB .
staticmethod
decorador permite chamar a função na classe e em uma instância (essa solução falha ao chamar a função em uma instância).
class C: def callme(): print('called'); C.callme()
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 podem ser criados assim (embora seja um pouco mais Pythonic usar sublinhados em vez do CamelCase para métodos):
class ClassName(object):
@staticmethod
def static_method(kwarg1=None):
'''return a value that is a function of kwarg1'''
O exemplo acima usa a sintaxe do decorador. Essa 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)
Isso pode ser usado exatamente como você descreveu:
ClassName.static_method()
Um exemplo interno de um método estático está str.maketrans()
no Python 3, que era uma função no string
módulo do Python 2.
Outra opção que pode ser usada como você descreve é classmethod
: a diferença é que o método de classe obtém a classe como primeiro argumento implícito e, se for subclassificado, obtém a subclasse como 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'''
Observe que esse cls
não é um nome obrigatório para o primeiro argumento, mas os codificadores Python mais experientes o considerarão mal feito se você usar qualquer outra coisa.
Estes são normalmente usados como construtores alternativos.
new_instance = ClassName.class_method()
Um exemplo embutido é dict.fromkeys()
:
new_dict = dict.fromkeys(['key1', 'key2'])
Além das particularidades de como os objetos do método estático se comportam, há um certo tipo de beleza que você pode encontrar com eles quando se trata de organizar o código no nível do 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, torna-se um pouco mais intuitivo e auto-documentado no contexto em que certos componentes devem ser usados e é ideal para nomear casos de teste distintos, além de ter uma abordagem direta de como os módulos de teste são mapeados para módulos reais sob testes para puristas .
Costumo achar viável aplicar essa abordagem à organização do código de utilidade de um projeto. Muitas vezes, as pessoas imediatamente correm para criar um utils
pacote e terminam com 9 módulos, dos quais um tem 120 LOC e o restante são duas dúzias de LOC, na melhor das hipóteses. Prefiro começar com isso e convertê-lo em um pacote e criar módulos apenas para os animais que realmente os merecem:
# 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 seja 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 esse método, as funções que modificam ou usam o estado interno do objeto (têm efeitos colaterais) podem ser mantidas na classe e as funções reutilizáveis do utilitário podem ser movidas para fora.
Digamos que esse arquivo seja chamado dogs.py
. Para usá-los, você chamaria em dogs.barking_sound()
vez de dogs.Dog.barking_sound
.
Se você realmente precisa de um método estático para fazer parte da classe, pode usar o decorador staticmethod .
Portanto, 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 exemplo acima, o método add
é chamado pelo nome da classe e A
não pelo nome do objeto.
Os métodos estáticos do Python 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))
Resultado:
Resultado: 25
Usando @staticmethod
class Arithmetic:
# create add static method
@staticmethod
def add(x, y):
return x + y
print('Result:', Arithmetic.add(15, 10))
Resultado:
Resultado: 25
Encontro essa pergunta de tempos em tempos. O caso de uso e o exemplo de que gosto é:
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 da classe cmath, porque não há estado em um objeto cmath. No entanto, cmath é uma coleção de métodos todos relacionados de alguma forma. No meu exemplo acima, todas as funções no cmath atuam em números complexos de alguma maneira.
@staticmethod
decoração ou usar um ponteiro de função, quando você pode simplesmente evitar o primeiroself
parâmetro? Bem, para um objetoa
, você não será capaz de chamadaa.your_static_method()
, o que é permitido em outros idiomas, mas é assim mesmo considerado uma má prática eo compilador sempre adverte sobre isso