Pregunta

¿Es posible disponer de métodos estáticos en Python para que pueda llamarlos sin inicializar una clase, como:

ClassName.StaticMethod ( )
¿Fue útil?

Solución

Sí, usando el métodoestático decorador

class MyClass(object):
    @staticmethod
    def the_static_method(x):
        print x

MyClass.the_static_method(2) # outputs 2

Tenga en cuenta que algunos código podría utilizar el viejo método de la definición de un método estático, usando staticmethod como una función más que un decorador. Esto sólo debe utilizarse si usted tiene que apoyar a las versiones antiguas de Python (2.2 y 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

Esto es totalmente idéntico al primer ejemplo (usando @staticmethod), simplemente no usando la sintaxis decorador agradable

Por último, utilizar staticmethod() con moderación! Hay muy pocas situaciones en las static-métodos son necesarios en Python, y he visto que utilizan muchas veces en una función separada "de alto nivel" habría sido más claro.


El siguiente es citamos la documentación: :

  

Un método estático no recibe un primer argumento implícito. Para declarar un método estático, utilice este idioma:

class C:
    @staticmethod
    def f(arg1, arg2, ...): ...
     

La forma @staticmethod es una función decorador - véase la descripción de las definiciones de funciones en Las definiciones de funciones para más detalles.

     

Se le puede llamar, ya sea en la clase (como C.f()) o en una instancia (como C().f()). La instancia se ignora a excepción de su clase.

     

Los métodos estáticos en Python son similares a los encontrados en Java o C ++. Para un concepto más avanzado, consulte classmethod() .

     

Para más información sobre los métodos estáticos, consulte la documentación en la jerarquía de tipo estándar en La jerarquía de tipo estándar .

     

Nuevo en la versión 2.2.

     

cambiado en la versión 2.4:. Sintaxis de la función decoradora añadió

Otros consejos

Steven derecha. Para responder a la pregunta original, a continuación, con el fin de establecer un método de clase, asumen que el primer argumento no va a ser una instancia de la llamada, y luego asegurarse de que sólo se llama al método de la clase.

(Tenga en cuenta que esta respuesta se refiere a 3.x de Python En Python 2.x obtendrá un TypeError para llamar al método en la clase en sí.)

Por ejemplo:

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)

En este código, el método "RollCall" asume que el primer argumento no es una instancia (como lo sería si se llama por una instancia en lugar de una clase). Mientras "RollCall" se llama de la clase en lugar de una instancia, el código funciona bien. Si tratamos de llamar "RollCall" de una instancia, por ejemplo:.

rex.rollCall(-1)

Sin embargo, causaría una excepción a ser elevado, ya que enviaría dos argumentos:. Sí mismo y -1, y "RollCall" sólo está definido para aceptar un argumento

A propósito, rex.rollCall () enviaría el número correcto de argumentos, sino que también causar una excepción a ser levantado porque ahora n se representa una instancia de perro (es decir, rex) cuando la función de espera n sea numérica.

Aquí es donde la decoración viene en: Si nos preceden al método "RollCall" con

@staticmethod

A continuación, al afirmar explícitamente que el método es estático, incluso podemos llamarlo desde una instancia. Ahora,

rex.rollCall(-1)

funcionaría. La inserción de @staticmethod antes de una definición del método y, a continuación, se detiene una instancia de enviándose como un argumento.

Puede verificar esto al tratar el siguiente código con y sin la línea @staticmethod comentado.

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)

Sí, echa un vistazo a la métodoestático decorador:

>>> class C:
...     @staticmethod
...     def hello():
...             print "Hello World"
...
>>> C.hello()
Hello World

En realidad, no es necesario utilizar el decorador @staticmethod. Sólo se declara un método (que no espera el parámetro auto) y lo llaman de la clase. El decorador es sólo para los casos que desea ser capaz de llamarlo desde una instancia así (que no era lo que quería hacer)

En su mayoría, sólo tiene que utilizar funciones aunque ...

  

Los métodos estáticos en Python?

     

¿Es posible disponer de métodos estáticos en Python para que pueda llamarlos   sin inicializar una clase, como:

ClassName.StaticMethod()

Sí, los métodos estáticos se pueden crear como esto (aunque es un poco más Pythonic para utilizar guiones en lugar de CamelCase para los métodos):

class ClassName(object):

    @staticmethod
    def static_method(kwarg1=None):
        '''return a value that is a function of kwarg1'''

Lo anterior utiliza la sintaxis decorador. Esta sintaxis es equivalente a

class ClassName(object):

    def static_method(kwarg1=None):
        '''return a value that is a function of kwarg1'''

    static_method = staticmethod(static_method)

Esto puede ser usado tal como lo describió:

ClassName.static_method()

Un ejemplo orden interna de un método estático se str.maketrans() en Python 3, que era una función en el módulo string en Python 2.


Otra opción que se puede utilizar como usted describe es la classmethod, la diferencia es que el classmethod obtiene la clase como primer argumento implícito, y si subclase, luego se pone la subclase como primer 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'''

Tenga en cuenta que cls no es un nombre requerido para el primer argumento, pero los programadores de Python más experimentados lo considerarán mal hecho si se utiliza cualquier otra cosa.

Estos se utilizan típicamente como constructores alternativos.

new_instance = ClassName.class_method()

Un ejemplo incorporado es dict.fromkeys():

new_dict = dict.fromkeys(['key1', 'key2'])

Aparte de las particularidades de la forma objetos método estático comportan, allí es un cierto tipo de belleza que puede golpear con ellos cuando se trata de organizar el código de nivel 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

Ahora se hace un poco más intuitiva y auto-documentado en qué contexto ciertos componentes están destinados a ser utilizados y se filtra hacia fuera idealmente para dar nombre a los casos de prueba distintos, además de tener un enfoque directo a la forma en módulos de prueba se asignan a módulos reales menores pruebas para puristas.

Con frecuencia resulta viable para aplicar este enfoque para organizar código de la utilidad de un proyecto. Muy a menudo, la gente se apresura inmediatamente y crean un paquete utils y terminan con 9 módulos de los cuales uno tiene 120 LOC y el resto son dos docenas LOC en el mejor. Prefiero comenzar con esto y convertirlo en un paquete y crear módulos sólo para las bestias que realmente los merecen:

# 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

Tal vez la opción más simple es sólo para poner esas funciones fuera de la clase:

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, las funciones que modifican o utilizan el estado del objeto interno (tienen efectos secundarios) se puede mantener en la clase, y las funciones de utilidad reutilizables se pueden mover fuera.

Digamos que este archivo se llama dogs.py. Para utilizar estos, que se dice dogs.barking_sound() en lugar de dogs.Dog.barking_sound.

Si realmente necesita un método estático para formar parte de la clase, se puede utilizar el rel="noreferrer"> decorador.

Por lo tanto, los métodos estáticos son los métodos que se pueden llamar sin crear el objeto de una clase. Por ejemplo: -

    @staticmethod
    def add(a, b):
        return a + b

b = A.add(12,12)
print b

En el add ejemplo método anterior es llamado por el nombre de la clase no A el nombre de objeto.

Los métodos estáticos Python se pueden crear de dos formas.

  1. Uso métodoestático ()

    class Arithmetic:
        def add(x, y):
            return x + y
    # create add static method
    Arithmetic.add = staticmethod(Arithmetic.add)
    
    print('Result:', Arithmetic.add(15, 10))
    

Salida:

Resultado: 25

  1. Uso @staticmethod

    class Arithmetic:
    
    # create add static method
    @staticmethod
    def add(x, y):
        return x + y
    
    print('Result:', Arithmetic.add(15, 10))
    

Salida:

Resultado: 25

Me encuentro con esta pregunta de vez en cuando. El caso de uso y el ejemplo que yo soy aficionado es:

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']
>>> 

No tiene sentido crear un objeto de la clase cmath, porque no hay un estado de un objeto cmath. Sin embargo, cmath es una colección de métodos que están todos relacionados de alguna manera. En el ejemplo anterior, todas las funciones en acto cmath en números complejos de alguna manera.

scroll top