Statische Methoden in Python?

1719

Ist es möglich, statische Methoden in Python zu haben, die ich aufrufen könnte, ohne eine Klasse zu initialisieren, wie:

ClassName.static_method()
Joan Venge
quelle

Antworten:

2026

Ja, mit dem StaticMethod Decorator

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

MyClass.the_static_method(2)  # outputs 2

Beachten Sie, dass in einigen Codes möglicherweise die alte Methode zum Definieren einer statischen Methode verwendet wird, die staticmethodals Funktion und nicht als Dekorator verwendet wird. 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 (using @staticmethod), nur ohne die nette Decorator-Syntax

Schließlich staticmethod()sparsam verwenden! Es gibt nur sehr wenige Situationen, in denen statische Methoden in Python erforderlich sind, und ich habe gesehen, dass sie oft verwendet wurden, wenn eine separate Funktion der "obersten Ebene" klarer gewesen wäre.


Das Folgende ist aus der Dokumentation wörtlich: :

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, ...): ...

Die @staticmethod Form ist eine Funktion Dekorateur - die Beschreibung von Funktionsdefinitionen in siehe Funktionsdefinitionen für weitere Einzelheiten.

Es kann entweder für die Klasse (z. B. C.f()) oder für eine Instanz (z. B. C().f()) aufgerufen werden . Die Instanz wird bis auf ihre Klasse ignoriert.

Statische Methoden in Python ähneln denen in Java oder C ++. Ein weiterführendes Konzept finden Sie unter classmethod().

Weitere Informationen zu statischen Methoden finden Sie in der Dokumentation zur Standardtyphierarchie unter Die Standardtyphierarchie .

Neu in Version 2.2.

In Version 2.4 geändert: Syntax des Funktionsdekorators hinzugefügt.

dbr
quelle
15
Warum @staticmethodDekoration hinzufügen oder einen Funktionszeiger verwenden, wenn Sie einfach den ersten selfParameter vermeiden können ? Nun, für ein Objekt akönnen Sie nicht aufrufen a.your_static_method(), was in anderen Sprachen erlaubt ist, aber es wird trotzdem als schlechte Praxis angesehen und der Compiler warnt immer davor
SomethingSomething
1
Ich verwende Python 2.7.12. Mit @staticmethod decorator kann ich die erste definierte statische Methode nicht aufrufen. Sein givin Fehler: TypeError: 'staticmethod' Objekt ist nicht aufrufbar
Supratim Samantray
Supratim Samantray, bist du sicher? denn hier ist klar angegeben, dass es nach 2.4 verwendet werden kann.
Realslimshanky
11
@SomethingSomething: Wenn Sie den Variablennamen "self" nicht verwenden, aber den Dekorator nicht hinzufügen, ist das erste Argument, z. B. arg1, immer noch der Verweis auf die self-Instanz. Der Name selbst ist nur eine Konvention.
George Moutsopoulos
1
@ GeorgeMoutsopoulos - allgemein vereinbart. Aber - Sie können die Methode trotzdem so aufrufen ClassName.methodName(), als wäre sie statisch, und dann selfwird der Methode keine bereitgestellt. Wie Sie sagten, ist es weiterhin möglich, diese Methode auch als aufzurufen ClassInstance.methodName(), und sie selfwird unabhängig von ihrem Namen als erster Parameter bereitgestellt.
Etwas Etwas
220

Ich denke, dass Steven tatsächlich Recht hat . Um die ursprüngliche Frage zu beantworten, nehmen Sie zum Einrichten einer Klassenmethode einfach an, dass das erste Argument keine aufrufende Instanz ist, und stellen Sie dann sicher, dass Sie die Methode nur aus der Klasse aufrufen.

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

Zum Beispiel:

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.

rex.rollCall(-1)

Es würde jedoch eine Ausnahme auslösen, da zwei Argumente gesendet würden: sich selbst und -1, und "rollCall" ist nur so definiert, dass ein Argument akzeptiert wird.

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

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

@staticmethod

Wenn wir dann 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 sich eine Instanz als Argument selbst sendet.

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

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)
Richard Ambler
quelle
8
Das erste Beispiel (Aufruf nach Klasse ohne @staticmethod) funktioniert bei Python 2.7 nicht. Ich erhalte "TypeError: ungebundene Methode rollCall () muss mit Dog-Instanz als erstem Argument aufgerufen werden (stattdessen int-Instanz erhalten)"
tba
2
Das funktioniert nicht. Sowohl Dog.rollCall (-1) als auch rex.rollCall (-1) geben dasselbe zurückTypeError: unbound method rollCall() must be called with Dog instance as first argument (got int instance instead)
Mittenchops
3
@MestreLion Ich denke, dies ist kein großer Vorteil, da es nur statische und Instanzmethoden durcheinander bringt und eine wie die andere aussehen lässt. Wenn Sie wissen, dass eine Methode statisch ist, sollten Sie als statische Methode darauf zugreifen. Die Tatsache, dass die Methode Ihre Instanz nicht benötigt oder verwendet, sollte überall dort selbstverständlich sein, wo Sie die Methode verwenden. Ich benutze immer T.my_static_method()oder type(my_t_instance).my_static_method(), da dies klarer ist und sofort klar macht, dass ich eine statische Methode aufrufe.
Asad Saeeduddin
81

Ja, sehen Sie sich den StaticMethod Decorator an:

>>> class C:
...     @staticmethod
...     def hello():
...             print "Hello World"
...
>>> C.hello()
Hello World
Paolo Bergantino
quelle
54

Sie müssen den @staticmethodDekorateur nicht wirklich benutzen . Deklarieren Sie einfach eine Methode (die den Parameter self nicht erwartet) und rufen Sie sie von der Klasse aus auf. Der Dekorateur ist nur für den Fall da, dass Sie ihn auch von einer Instanz aus aufrufen möchten (was Sie nicht wollten).

Meistens verwenden Sie jedoch nur Funktionen ...

hichris123
quelle
Dies würde für Python 2.5.2 nicht funktionieren. class Dummy: def static1(): print "hello from static1" @staticmethod def static2(): print "hello from static2" Dummy.static2() Dummy.static1() Ausgabe: Hallo von static2 Traceback <letzter Aufruf zuletzt>: Datei "ll.py", Zeile 46, in <module> Dummy.static1 () TypeError: ungebundene Methode static1 () muss sein mit Dummy-Instanz als erstes Argument aufgerufen (bekam stattdessen nichts)
Mahori
7
Dies funktioniert nicht innerhalb einer Klasse. Python wird selfals erstes Argument übergeben, es sei denn, Sie sagen es nicht. (siehe: Dekorateur)
Navin
9
Tatsächlich ist dies in 2.7 falsch und ab 3.X legal (in 3.2 gut getestet). Das heißt, Sie können eine Methode nicht aus dem Kontext einer Klasse ohne den @ staticmethod-Dekorator in 2.7 und darunter aufrufen. In 3.2 funktioniert es und fügt eine selfReferenz entsprechend ein, je nachdem, wie es aufgerufen wird. Testfall: pastebin.com/12DDV7DB .
Spinkus
2
Technisch korrekt, aber eine schreckliche Lösung. Mit dem staticmethodDekorator kann die Funktion sowohl für die Klasse als auch für eine Instanz aufgerufen werden (diese Lösung schlägt fehl, wenn die Funktion für eine Instanz aufgerufen wird).
Ethan Furman
Eine Methode kann wie jedes andere Attribut eines Objekts in Punktnotation aufgerufen werden. class C: def callme(): print('called'); C.callme()
Pouya
32

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 wie folgt erstellt werden (obwohl es etwas pythonischer ist , für Methoden Unterstriche anstelle von CamelCase zu verwenden):

class ClassName(object):

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

Das obige verwendet die Decorator-Syntax. 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 genau so verwendet werden, wie Sie es beschrieben haben:

ClassName.static_method()

Ein eingebautes Beispiel für eine statische Methode ist str.maketrans()Python 3, eine Funktion im stringModul in Python 2.


Eine andere Option, die wie beschrieben verwendet werden kann, ist die classmethod: Der Unterschied besteht darin, dass die Klassenmethode die Klasse als implizites erstes Argument erhält. Wenn sie untergeordnet ist, 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 dies clskein erforderlicher Name für das erste Argument ist, aber die meisten erfahrenen Python-Codierer halten es für schlecht, wenn Sie etwas anderes verwenden.

Diese werden typischerweise als alternative Konstruktoren verwendet.

new_instance = ClassName.class_method()

Ein eingebautes Beispiel ist dict.fromkeys():

new_dict = dict.fromkeys(['key1', 'key2'])
Aaron Hall
quelle
11

Abgesehen von den Besonderheiten des Verhaltens statischer Methodenobjekte gibt es eine bestimmte Art von Schönheit, die Sie bei der Organisation Ihres Codes auf Modulebene mit ihnen erzielen können.

# 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 jetzt etwas intuitiver und selbstdokumentierender, in welchem ​​Kontext bestimmte Komponenten verwendet werden sollen, und es eignet sich ideal für die Benennung bestimmter Testfälle sowie für einen einfachen Ansatz, wie Testmodule tatsächlichen Modulen zugeordnet werden, die für Puristen getestet werden .

Ich finde es häufig sinnvoll, diesen Ansatz auf die Organisation des Dienstprogrammcodes eines Projekts anzuwenden. Sehr oft beeilen sich die Leute sofort und erstellen ein utilsPaket und erhalten 9 Module, von denen eines 120 LOC hat und der Rest bestenfalls zwei Dutzend LOC sind. Ich ziehe es vor, damit zu beginnen und es in ein Paket umzuwandeln und Module nur für die Bestien 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
Filip Dupanović
quelle
10

Die vielleicht einfachste Möglichkeit besteht darin, diese Funktionen 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 und die wiederverwendbaren Dienstprogrammfunktionen nach draußen verschoben werden.

Angenommen, diese Datei wird aufgerufen dogs.py. Um diese zu verwenden, würden Sie dogs.barking_sound()statt anrufen dogs.Dog.barking_sound.

Wenn Sie wirklich eine statische Methode müssen Teil der Klasse sein, können Sie das verwenden static Dekorateur.

Matt Woelk
quelle
1

Statische Methoden sind also die Methoden, die aufgerufen werden können, ohne das Objekt einer Klasse zu erstellen. Beispielsweise :-

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

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

Im obigen Beispiel wird die Methode adddurch den Klassennamen und Anicht durch den Objektnamen aufgerufen .

Aman Raheja
quelle
-3

Python Statische Methoden können auf zwei Arten erstellt werden.

  1. Verwenden der statischen Methode ()

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

Ausgabe:

Ergebnis: 25

  1. Verwenden von @staticmethod

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

Ausgabe:

Ergebnis: 25

Codemaker
quelle
Sie haben nur Beispiele bereitgestellt und die Möglichkeiten erläutert, wie Sie dies tun können. Sie haben nicht erklärt, was die Methoden bedeuten.
Zixuan
-4

Ich begegne dieser Frage von Zeit zu Zeit. Der Anwendungsfall und das Beispiel, die ich mag, sind:

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 ein cmath-Objekt keinen Status enthält. Cmath ist jedoch eine Sammlung von Methoden, die alle in irgendeiner Weise miteinander verbunden sind. In meinem obigen Beispiel wirken alle Funktionen in cmath auf komplexe Weise auf komplexe Zahlen.

user1928764
quelle
Sie haben die Frage nicht beantwortet, sondern stattdessen ein Beispiel angegeben.
Zixuan