Pergunta

É possível ter métodos estáticos em Python para que eu possa chamá-los sem inicializar uma classe, como:

ClassName.StaticMethod ( )
Foi útil?

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 (como C().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.

  1. 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

  1. 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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top