Ist es möglich, statische Methoden in Python zu haben, die ich aufrufen könnte, ohne eine Klasse zu initialisieren, wie:
ClassName.static_method()
Ist es möglich, statische Methoden in Python zu haben, die ich aufrufen könnte, ohne eine Klasse zu initialisieren, wie:
ClassName.static_method()
Antworten:
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 staticmethod
als 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.
ClassName.methodName()
, als wäre sie statisch, und dann self
wird der Methode keine bereitgestellt. Wie Sie sagten, ist es weiterhin möglich, diese Methode auch als aufzurufen ClassInstance.methodName()
, und sie self
wird unabhängig von ihrem Namen als erster Parameter bereitgestellt.
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 TypeError
zum 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)
TypeError: unbound method rollCall() must be called with Dog instance as first argument (got int instance instead)
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.
Ja, sehen Sie sich den StaticMethod Decorator an:
>>> class C:
... @staticmethod
... def hello():
... print "Hello World"
...
>>> C.hello()
Hello World
Sie müssen den @staticmethod
Dekorateur 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 ...
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)
self
als erstes Argument übergeben, es sei denn, Sie sagen es nicht. (siehe: Dekorateur)
self
Referenz entsprechend ein, je nachdem, wie es aufgerufen wird. Testfall: pastebin.com/12DDV7DB .
staticmethod
Dekorator 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).
class C: def callme(): print('called'); C.callme()
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 string
Modul 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 cls
kein 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'])
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 utils
Paket 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
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.
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 add
durch den Klassennamen und A
nicht durch den Objektnamen aufgerufen .
Python Statische Methoden können auf zwei Arten erstellt werden.
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
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
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.
@staticmethod
Dekoration hinzufügen oder einen Funktionszeiger verwenden, wenn Sie einfach den erstenself
Parameter vermeiden können ? Nun, für ein Objekta
können Sie nicht aufrufena.your_static_method()
, was in anderen Sprachen erlaubt ist, aber es wird trotzdem als schlechte Praxis angesehen und der Compiler warnt immer davor