Frage Statische Methoden in Python?


Ist es möglich, in Python statische Methoden zu verwenden, damit ich sie aufrufen kann, ohne eine Klasse zu initialisieren, wie:

ClassName.StaticMethod ( )

1391
2018-04-09 21:23


Ursprung


Antworten:


Ja, mit dem statische Methode Dekorateur

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

MyClass.the_static_method(2) # outputs 2

Beachten Sie, dass bei einigen Code möglicherweise die alte Methode zum Definieren einer statischen Methode verwendet wird staticmethod als Funktion und nicht als Dekorateur. Dies sollte nur verwendet werden, wenn Sie alte Versionen von Python (2.2 und 2.3) unterstützen müssen

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

MyClass.the_static_method(2) # outputs 2

Dies ist völlig identisch mit dem ersten Beispiel (mit @staticmethod), einfach nicht die nette Dekoratorsyntax verwenden

Schließlich, verwenden Sie staticmethod() sparsam! Es gibt sehr wenige Situationen, in denen statische Methoden in Python notwendig sind, und ich habe sie oft benutzt, wo eine separate "Top-Level" -Funktion klarer gewesen wäre.


Das Folgende ist wörtlich aus der Dokumentation::

Eine statische Methode erhält kein implizites erstes Argument. Verwenden Sie dieses Idiom, um eine statische Methode zu deklarieren:

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

Das @ staticmethod-Formular ist eine Funktion Dekorateur - siehe Beschreibung der Funktionsdefinitionen in Funktionsdefinitionen für Details.

Es kann entweder auf der Klasse (wie z. B. C.f()) oder auf einer Instanz (wie z C().f()). Die Instanz wird außer für ihre Klasse ignoriert.

Die statischen Methoden in Python ähneln denen in Java oder C ++. Für ein fortgeschrittenes Konzept, siehe classmethod().

Weitere Informationen zu statischen Methoden finden Sie in der Dokumentation zur Standard-Typhierarchie in Die Standardtyphierarchie.

Neu in Version 2.2.

Geändert in Version 2.4: Syntax der Funktion Decorator hinzugefügt.


1696
2018-04-09 21:24



ich denke, dass Steven hat eigentlich Recht. Um die ursprüngliche Frage zu beantworten, nehmen Sie einfach an, dass das erste Argument keine aufrufende Instanz sein wird, und stellen Sie dann sicher, dass Sie die Methode nur von der Klasse aufrufen, um eine Klassenmethode einzurichten.

(Beachten Sie, dass sich diese Antwort auf Python 3.x bezieht. In Python 2.x erhalten Sie eine TypeError um die Methode für die Klasse selbst aufzurufen.)

Beispielsweise:

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)

In diesem Code geht die Methode "rollCall" davon aus, dass das erste Argument keine Instanz ist (wie es wäre, wenn es von einer Instanz anstelle einer Klasse aufgerufen würde). Solange "rollCall" von der Klasse und nicht von einer Instanz aufgerufen wird, funktioniert der Code einwandfrei. Wenn wir versuchen, "rollCall" von einer Instanz aus aufzurufen, z. B .:

rex.rollCall(-1)

Es würde jedoch eine Ausnahme ausgelöst werden, da es zwei Argumente senden würde: sich selbst und -1, und "rollCall" ist nur definiert, um ein Argument zu akzeptieren.

Übrigens würde rex.rollCall () die richtige Anzahl von Argumenten senden, würde aber auch eine Ausnahme auslösen, da nun n eine Dog-Instanz (d. H. Rex) darstellen würde, wenn die Funktion erwartet, dass n numerisch ist.

Hier kommt die Dekoration ins Spiel: Wenn wir der "rollCall" -Methode mit

@staticmethod

Indem wir explizit angeben, dass die Methode statisch ist, können wir sie sogar von einer Instanz aus aufrufen. Jetzt,

rex.rollCall(-1)

würde funktionieren. Das Einfügen von @staticmethod vor einer Methodendefinition verhindert dann, dass eine Instanz sich selbst als Argument sendet.

Sie können dies überprüfen, indem Sie den folgenden Code mit und ohne @staticmethod-Zeile auskommentiert auskommentieren.

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



Ja, schau dir das an statische Methode Dekorateur:

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

74
2018-04-09 21:24



Du brauchst das nicht wirklich zu benutzen @staticmethod Dekorateur. Einfach eine Methode deklarieren (die den Parameter self nicht erwartet) und sie aus der Klasse aufrufen. Der Decorator ist nur für den Fall vorhanden, dass Sie ihn auch von einer Instanz aufrufen können (was Sie nicht wollten)

Meistens benutzen Sie nur Funktionen, aber ...


43
2018-04-10 16:00



Statische Methoden in Python?

Ist es möglich, statische Methoden in Python zu haben, damit ich sie aufrufen kann?   ohne eine Klasse zu initialisieren, wie:

ClassName.StaticMethod()

Ja, statische Methoden können so erstellt werden (obwohl es ein bisschen mehr ist Pythonisch Verwenden von Unterstrichen anstelle von CamelCase für Methoden):

class ClassName(object):

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

Das obige verwendet die Dekoratorsyntax. Diese Syntax entspricht

class ClassName(object):

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

    static_method = staticmethod(static_method)

Dies kann wie beschrieben verwendet werden:

ClassName.static_method()

Ein eingebautes Beispiel für eine statische Methode ist str.maketrans() in Python 3, das war eine Funktion in der string Modul in Python 2.


Eine weitere Möglichkeit, die Sie verwenden können, ist die classmethodDer Unterschied besteht darin, dass die Klassenmethode die Klasse als implizites erstes Argument erhält. Wenn sie unterklassifiziert wird, erhält sie die Unterklasse als implizites erstes Argument.

class ClassName(object):

    @classmethod
    def class_method(cls, kwarg1=None):
        '''return a value that is a function of the class and kwarg1'''

Beachten Sie, dass cls ist kein erforderlicher Name für das erste Argument, aber die meisten erfahrenen Python-Programmierer halten es für schlecht, wenn Sie etwas anderes verwenden.

Diese werden normalerweise als alternative Konstruktoren verwendet.

new_instance = ClassName.class_method()

Ein eingebautes Beispiel ist dict.fromkeys():

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

28
2018-01-24 04:34



Abgesehen von den Besonderheiten wie statische Methodenobjekte Benimm dich, es gibt eine gewisse Schönheit, die du mit ihnen treffen kannst, wenn es darum geht, deinen Code auf Modulebene zu organisieren.

# 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

Es wird nun etwas intuitiver und selbstdokumentierender, in welchem ​​Kontext bestimmte Komponenten verwendet werden sollen, und es eignet sich ideal für die Benennung verschiedener Testfälle sowie für einen einfachen Ansatz, wie Testmodule im Test für Puristen den tatsächlichen Modulen zugeordnet werden .

Ich halte es häufig für sinnvoll, diesen Ansatz für die Organisation des Utility-Codes eines Projekts anzuwenden. Ziemlich häufig eilen Leute sofort und schaffen ein utils Paket und am Ende mit 9 Modulen, von denen eines 120 LOC hat und der Rest sind zwei Dutzend LOC bestenfalls. Ich ziehe es vor, damit zu beginnen und es in ein Paket umzuwandeln und Module nur für die Tiere zu erstellen, die sie wirklich verdienen:

# 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



Vielleicht ist die einfachste Option, diese Funktionen einfach außerhalb der Klasse zu platzieren:

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"

Mit dieser Methode können Funktionen, die den internen Objektstatus ändern oder verwenden (Nebenwirkungen haben), in der Klasse beibehalten werden, und die wiederverwendbaren Dienstprogrammfunktionen können nach außen verschoben werden.

Nehmen wir an, diese Datei wird aufgerufen dogs.py. Um diese zu verwenden, würden Sie anrufen dogs.barking_sound() Anstatt von dogs.Dog.barking_sound.

Wenn Sie wirklich eine statische Methode benötigen, um Teil der Klasse zu sein, können Sie die statische Methode Dekorateur.


7
2017-07-30 16:10



Ich stoße von Zeit zu Zeit auf diese Frage. Der Anwendungsfall und das Beispiel, das mir gefällt, ist:

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

Es ist nicht sinnvoll, ein Objekt der Klasse cmath zu erstellen, da in einem cmath-Objekt kein Status vorhanden ist. Cmath ist jedoch eine Sammlung von Methoden, die alle in irgendeiner Weise verwandt sind. In meinem Beispiel oben wirken sich alle Funktionen in cmath auf komplexe Zahlen aus.


-1
2018-01-08 06:53