Pregunta Métodos estáticos en Python?


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

ClassName.StaticMethod ( )

1391
2018-04-09 21:23


origen


Respuestas:


Sí, usando el método está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ódigos pueden usar el antiguo método de definición de un método estático, utilizando staticmethod como una función en lugar de un decorador. Esto solo debe usarse si tiene que admitir 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 completamente idéntico al primer ejemplo (usando @staticmethod), simplemente no usa la buena sintaxis del decorador

Finalmente, usa staticmethod() ¡escasamente! Hay muy pocas situaciones en las que los métodos estáticos sean necesarios en Python, y los he visto muchas veces en los que una función separada de "nivel superior" hubiera sido más clara.


Lo siguiente es textualmente de la documentación::

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

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

El formulario @staticmethod es una función decorador - ver la descripción de las definiciones de funciones en Definiciones de funciones para detalles.

Se puede invocar en la clase (como C.f()) o en una instancia (como C().f()) La instancia se ignora excepto por su clase.

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

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

Nuevo en la versión 2.2.

Modificado en la versión 2.4: se agregó la sintaxis del decorador de función.


1696
2018-04-09 21:24



Creo que Steven tiene razón. Para responder la pregunta original, entonces, para configurar un método de clase, simplemente suponga que el primer argumento no será una instancia de llamada, y luego asegúrese de llamar solo al método de la clase.

(Tenga en cuenta que esta respuesta se refiere a Python 3.x. 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" supone que el primer argumento no es una instancia (como lo sería si una instancia lo llamara en lugar de una clase). Siempre que se llame a "rollCall" desde la clase en lugar de una instancia, el código funcionará correctamente. Si intentamos llamar a "rollCall" desde una instancia, por ejemplo:

rex.rollCall(-1)

sin embargo, provocaría una excepción porque enviaría dos argumentos: sí mismo y -1, y "rollCall" solo está definido para aceptar un argumento.

Incidentalmente, rex.rollCall () enviaría la cantidad correcta de argumentos, pero también provocaría una excepción porque ahora n representaría una instancia Dog (es decir, rex) cuando la función espera que n sea numérica.

Aquí es donde entra la decoración: Si precedemos al método "rollCall" con

@staticmethod

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

rex.rollCall(-1)

trabajaría. La inserción de @staticmethod antes de una definición de método, entonces, impide que una instancia se envíe a sí misma como un argumento.

Puede verificar esto probando el siguiente código con y sin la línea de @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)

176
2018-04-18 09:16



Sí, mira el método estático decorador:

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

74
2018-04-09 21:24



Realmente no necesitas usar el @staticmethod decorador. Acaba de declarar un método (que no espera el parámetro propio) y lo llama desde la clase. El decorador solo está allí en caso de que desee poder llamarlo desde una instancia también (que no era lo que quería hacer)

Sobre todo, solo usas funciones ...


43
2018-04-10 16:00



Métodos estáticos en Python?

¿Es posible tener métodos estáticos en Python para poder llamarlos?   sin inicializar una clase, como:

ClassName.StaticMethod()

Sí, los métodos estáticos se pueden crear de esta manera (aunque es un poco más Pythonic para utilizar guiones bajos 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 usa la sintaxis del 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 se puede usar tal como lo describió:

ClassName.static_method()

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


Otra opción que puede usarse como usted describe es la classmethod, la diferencia es que el método de clase obtiene la clase como un primer argumento implícito, y si se subclasifica, entonces obtiene la subclase como el 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 obligatorio para el primer argumento, pero la mayoría de los programadores de Python considerarán que está mal hecho si usas algo más.

Estos son típicamente usados ​​como constructores alternativos.

new_instance = ClassName.class_method()

Un ejemplo incorporado es dict.fromkeys():

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

28
2018-01-24 04:34



Aparte de las particularidades de cómo Objetos de método estático comportarse, hay un cierto tipo de belleza que puedes encontrar cuando se trata de organizar tu 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 vuelve un poco más intuitivo y autodocumentado, en cuyo contexto se deben usar ciertos componentes y se diseña idealmente para nombrar casos de prueba distintos, así como tener un enfoque directo de cómo los módulos de prueba se asignan a módulos reales en pruebas para puristas .

A menudo me resulta viable aplicar este enfoque para organizar el código de utilidad de un proyecto. Muy a menudo, la gente inmediatamente se apresura y crea un utils paquete y terminar con 9 módulos de los cuales uno tiene 120 LOC y el resto son dos docenas de LOC en el mejor de los casos. Prefiero comenzar con esto y convertirlo en un paquete y crear módulos solo 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

9
2017-12-29 19:47



Quizás la opción más simple es simplemente 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"

Con este método, las funciones que modifican o usan el estado interno del objeto (tienen efectos secundarios) pueden mantenerse en la clase, y las funciones de utilidad reutilizables se pueden mover al exterior.

Digamos que este archivo se llama dogs.py. Para usar estos, llamarías dogs.barking_sound() en lugar de dogs.Dog.barking_sound.

Si realmente necesita un método estático para formar parte de la clase, puede usar método estático decorador.


7
2017-07-30 16:10



Me encuentro con esta pregunta de vez en cuando. El caso de uso y el ejemplo que me gusta son:

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 clase cmath, porque no hay estado en un objeto cmath. Sin embargo, cmath es una colección de métodos que están relacionados de alguna manera. En mi ejemplo anterior, todas las funciones en cmath actúan en números complejos de alguna manera.


-1
2018-01-08 06:53