Was ist der Vorteil der Verwendung statischer Methoden in Python?

89

Ich bin in Python auf einen ungebundenen Methodenfehler mit dem Code gestoßen

import random

class Sample(object):
'''This class defines various methods related to the sample'''

    def drawSample(samplesize,List):
        sample=random.sample(List,samplesize)
        return sample

Choices=range(100)
print Sample.drawSample(5,Choices)

Nachdem ich hier viele hilfreiche Beiträge gelesen hatte, überlegte ich, wie ich @staticmethodoben hinzufügen könnte , damit der Code funktioniert. Ich bin ein Python-Neuling. Kann jemand bitte erklären, warum man statische Methoden definieren möchte? Oder warum sind nicht alle Methoden als statische Methoden definiert?

Curious2learn
quelle
1
Dies ist eine seltsame Frage. Statische Methoden sind ein Design Notwendigkeit . Es ist kein "Vorteil". Sie benutzen sie, weil Sie müssen. Es ist ein Konstruktionsmerkmal einer Klasse, statische Methoden zu haben. Fragen Sie sich, was statische Methoden überhaupt sind? Ich denke, die Frage könnte umformuliert werden, um klarer zu definieren, was Sie wissen müssen.
S.Lott
15
Nein, ich wollte nicht wissen, was sie sind. Was ich wissen wollte war, warum es eine "Notwendigkeit" ist, die aus den Antworten anderer deutlich geworden ist. Dann würden Sie es eher definieren als die nicht statischen Methoden. Vielen Dank.
Curious2learn
3
@ S.Lott: Wann ist die Verwendung einer statischen Methode eine Notwendigkeit im Gegensatz zur Verwendung einer normalen Klassenmethode? Soweit ich das beurteilen kann, kann eine Klassenmethode alles, was eine statische Methode kann. Statische Methode hat "Vorteile", wie an anderer Stelle in diesem Beitrag aufgeführt, aber ich kann keine Gründe erkennen, warum eine Klassenmethode an keiner Stelle verwendet werden kann, an der eine statische Methode verwendet werden kann, was sie zur Notwendigkeit macht.
RFV5s

Antworten:

124

Statische Methoden können nur eingeschränkt verwendet werden, da sie keinen Zugriff auf die Attribute einer Instanz einer Klasse haben (wie dies bei einer regulären Methode der Fall ist) und keinen Zugriff auf die Attribute der Klasse selbst haben (wie dies bei einer Klassenmethode der Fall ist) ).

Daher sind sie für alltägliche Methoden nicht nützlich.

Sie können jedoch nützlich sein, um einige Dienstprogrammfunktionen zusammen mit einer Klasse zu gruppieren - z. B. eine einfache Konvertierung von einem Typ in einen anderen -, für die außer den angegebenen Parametern (und möglicherweise einigen für das Modul globalen Attributen) kein Zugriff auf Informationen erforderlich ist. )

Sie könnten außerhalb der Klasse platziert werden, aber eine Gruppierung innerhalb der Klasse kann sinnvoll sein, wenn sie nur dort anwendbar sind.

Sie können die Methode auch über eine Instanz oder die Klasse anstatt über den Modulnamen referenzieren, um dem Leser zu helfen, zu verstehen, auf welche Instanz die Methode bezogen ist.

Seltsames Denken
quelle
8
@ Curious2learn: Nicht alle , aber einige Methoden sind als statische Methoden nützlich. Stellen Sie sich eine Beispielklasse vor Locale, deren Instanzen Gebietsschemas (duh) sind. Eine getAvailableLocales()Methode wäre ein schönes Beispiel für eine statische Methode einer solchen Klasse: Sie gehört eindeutig zur Locale-Klasse, während sie eindeutig zu keiner bestimmten Instanz gehört.
MestreLion
... und es ist auch keine Klassenmethode, da sie möglicherweise nicht auf eine der Klassenmethoden zugreifen muss.
MestreLion
Ein Editor weist darauf hin, dass eine statische Methode auf die Klassenattribute zugreifen kann , indem sie explizit von der nach unten navigiert class_name.attribute, nur nicht cls.attributeoder self.attribute. Dies gilt für "öffentliche" Attribute. Konventionell sollten Sie auf diese Weise nicht auf Attribute zugreifen, die mit einem Unterstrich verborgen sind, oder auf Namen, die mit zwei Unterstrichen entstellt sind. Dies bedeutet auch, dass Ihr Code anfälliger wird, wenn Attribute die Positionen in der Vererbungshierarchie verschieben.
Oddthinking
Ein Zitat von Guido, das bei der Entscheidung hilft, wann statische Methoden verwendet werden sollen (niemals): "Wir alle wissen, wie begrenzt statische Methoden sind. (Sie sind im Grunde genommen ein Unfall - in den Python 2.2-Tagen, als ich Klassen und Deskriptoren neuen Stils erfand Ich wollte Klassenmethoden implementieren, aber zuerst verstand ich sie nicht und implementierte versehentlich zuerst statische Methoden. Dann war es zu spät, sie zu entfernen und nur Klassenmethoden bereitzustellen. "
Boris Churzin
185

Ausführliche Erläuterungen finden Sie in diesem Artikel .

TL; DR

1. Es beseitigt die Verwendung von selfArgumenten.

2. Es reduziert die Speichernutzung, da Python nicht für jedes instanziierte Objekt eine gebundene Methode instanziieren muss:

>>>RandomClass().regular_method is RandomClass().regular_method
False
>>>RandomClass().static_method is RandomClass().static_method
True
>>>RandomClass.static_method is RandomClass().static_method
True

3. Es verbessert die Lesbarkeit des Codes und bedeutet, dass die Methode nicht vom Status des Objekts selbst abhängt.

4. Es ermöglicht das Überschreiben von Methoden, da eine Unterklasse diese Methode nicht überschreiben könnte, wenn die Methode auf Modulebene (dh außerhalb der Klasse) definiert würde.

zanetu
quelle
3
Dies sollte die akzeptierte Antwort sein. Die Tatsache, dass die statische Methode für alle Instanzen und die Klasse selbst dasselbe Objekt sind, ist ein echter Vorteil, insbesondere wenn Sie viele Instanzen haben (z. B. jede Instanz für einen veränderlichen Datenbankdatensatz).
Zhuoyun Wei
+1 und stimme @ZhuoyunWei zu. Nur eine Antwort, die die wenigen Gründe erklärt, warum eine statische Methode manchmal einer Klassenmethode vorzuziehen ist (obwohl 1 und 3 wirklich der gleiche Grund sind).
Alex
1
Die beste Antwort auf "Warum statische Methode", aber die ursprüngliche Frage lautete auch "Warum sind nicht alle Methoden statisch?". Ein kurzes "kein Zugriff auf Instanzattribute" würde dies ebenfalls abdecken.
Exu
IMO ist der einzige wirkliche Vorteil, dass Sie es in einer Unterklasse überschreiben können, aber selbst das hat das Gefühl, dass Sie etwas falsch machen, was den OOP betrifft. In welchem ​​Anwendungsfall würden Sie das tun?
Boris Churzin
23

Dies ist nicht ganz der Punkt Ihrer eigentlichen Frage, aber da Sie gesagt haben, dass Sie ein Python-Neuling sind, wird es vielleicht hilfreich sein, und niemand anderes ist ganz herausgekommen und hat es explizit gesagt.

Ich hätte den obigen Code niemals repariert, indem ich die Methode zu einer statischen Methode gemacht hätte. Ich hätte entweder die Klasse verlassen und nur eine Funktion geschrieben:

def drawSample(samplesize,List):
    sample=random.sample(List,samplesize)
    return sample

Choices=range(100)
print drawSample(5,Choices)

Wenn Sie viele verwandte Funktionen haben, können Sie diese in einem Modul gruppieren, dh alle in derselben Datei ablegen, die sample.pybeispielsweise benannt ist. dann

import sample

Choices=range(100)
print sample.drawSample(5,Choices)

Oder ich hätte __init__der Klasse eine Methode hinzugefügt und eine Instanz mit nützlichen Methoden erstellt:

class Sample(object):
'''This class defines various methods related to the sample'''

    def __init__(self, thelist):
        self.list = thelist

    def draw_sample(self, samplesize):
        sample=random.sample(self.list,samplesize)
        return sample

choices=Sample(range(100))
print choices.draw_sample(5)

(Ich habe auch die Fallkonventionen im obigen Beispiel geändert, um sie an den von PEP 8 empfohlenen Stil anzupassen.)

Einer der Vorteile von Python ist, dass Sie nicht gezwungen werden, Klassen für alles zu verwenden. Sie können sie nur verwenden, wenn Daten oder Status vorhanden sind, die den Methoden zugeordnet werden sollen. Dafür sind Klassen vorgesehen. Andernfalls können Sie Funktionen verwenden, für die Funktionen vorgesehen sind.

Vicki Laidler
quelle
Danke für den Kommentar. In diesem Fall brauchte ich eine Klasse, weil ich mit der gezeichneten Probe arbeiten möchte. Nein, ich habe keine statische Methode verwendet, wollte aber etwas darüber lernen, da ich auf den Begriff gestoßen bin, als ich Informationen zu der Fehlermeldung nachgeschlagen habe, die ich erhalten habe. Ihr Ratschlag zum Sammeln der Funktionen in einem Modul ohne Definition einer Klasse wäre jedoch für andere Funktionen hilfreich, die ich benötige. So danke.
Curious2learn
4
+1: Das war eine nette Erklärung für einige Missverständnisse, die das OP hatte. Und Sie waren sehr ehrlich zu sagen, dass Sie seine Frage nach statischen Methoden nicht wirklich beantwortet haben, sondern eine viel bessere Lösung gegeben haben, indem Sie sagten, dass sein Problem überhaupt keinen Unterricht erfordert.
MestreLion
19

Warum sollte man statische Methoden definieren wollen ?

Angenommen , wir haben ein classgenannt Mathdann

Niemand wird ein Objekt erstellen class Math
und dann Methoden wie ceilund floorund darauf aufrufen fabswollen.

Also machen wir sie static.

Zum Beispiel tun

>> Math.floor(3.14)

ist viel besser als

>> mymath = Math()
>> mymath.floor(3.14)

Sie sind also irgendwie nützlich. Sie müssen keine Instanz einer Klasse erstellen, um sie zu verwenden.

Warum sind nicht alle Methoden als statische Methoden definiert? ?

Sie haben keinen Zugriff auf Instanzvariablen.

class Foo(object):
    def __init__(self):
        self.bar = 'bar'

    def too(self):
        print self.bar

    @staticmethod
    def foo():
        print self.bar

Foo().too() # works
Foo.foo() # doesn't work

Deshalb machen wir nicht alle Methoden statisch.

Pratik Deoghare
quelle
10
Aber warum nicht ein Paket Mathe? Python hat Pakete für die, die Sie nicht brauchen eine Klassendefinition einen Namespace zu erstellen.
Extraneon
6
@extraneon: Yup Alter, das weiß ich, aber ich wollte etwas Einfaches und Vertrautes zur Erklärung haben, also habe ich es benutzt Math. Deshalb habe ich groß geschrieben M.
Pratik Deoghare
6
Das OP hat nicht gefragt, was statische Methoden sind. Er fragte, was ihr Vorteil sei. Sie erklären, wie man sie benutzt, nicht wie sie nützlich sind. In Ihrem speziellen Beispiel wäre ein Namespace viel sinnvoller.
Javier
4
-1: Gute und korrekte Erklärung, aber ein sehr schlecht gewähltes Beispiel: Es gibt keinen Grund dafür, dass Sie sich überhaupt Mathzu einer Klasse zusammengeschlossen haben. Ein Modul passt besser. Versuchen Sie, ein Beispiel für eine Klasse zu finden, die als Klasse sinnvoll ist, und nicht eines, von dem "niemand ein Objekt erstellen möchte" .
MestreLion
3
Und dann ein Beispiel für einen legit Anwendungsfall gibt für einen (oder einige ) der Methoden Klassen statisch zu sein, aber nicht alle . Wenn alle Methoden einer Klasse statisch sind, sollte die Klasse ein Modul sein. Wenn keine statisch sind, beantworten Sie die Frage nicht.
MestreLion
13

Wenn Sie ein Funktionsobjekt von einer Objektinstanz aus aufrufen, wird es zu einer gebundenen Methode und das Instanzobjekt selbst wird als erstes Argument übergeben.

Wenn Sie ein classmethodObjekt (das ein Funktionsobjekt umschließt) für eine Objektinstanz aufrufen , wird die Klasse des Instanzobjekts als erstes Argument übergeben.

Wenn Sie ein staticmethodObjekt aufrufen (das ein Funktionsobjekt umschließt), wird kein implizites erstes Argument verwendet.

class Foo(object):

    def bar(*args):
        print args

    @classmethod
    def baaz(*args):
        print args

    @staticmethod
    def quux(*args):
        print args

>>> foo = Foo()

>>> Foo.bar(1,2,3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method bar() must be called with Foo instance as first argument (got int instance instead)
>>> Foo.baaz(1,2,3)
(<class 'Foo'>, 1, 2, 3)
>>> Foo.quux(1,2,3)
(1, 2, 3)

>>> foo.bar(1,2,3)
(<Foo object at 0x1004a4510>, 1, 2, 3)
>>> foo.baaz(1,2,3)
(<class 'Foo'>, 1, 2, 3)
>>> foo.quux(1,2,3)
(1, 2, 3)
Matt Anderson
quelle
3
+1: Zum Schluss eine gute Erklärung, was statische Methoden und Klassenmethoden sind. Auch wenn Sie nicht erklären , warum würde man jemals eine statische Methode verwenden möchten, zumindest erklärt man deutlich in einem einfachen Beispiel , was beide sind viel besser als die offiziellen Dokumente der Fall ist.
MestreLion
3

statische Methoden sind großartig, da Sie keine Instanz des Objekts deklarieren müssen, zu dem die Methode gehört.

Auf der Python-Website finden Sie eine hervorragende Dokumentation zu statischen Methoden:
http://docs.python.org/library/functions.html#staticmethod

David Fox
quelle
Danke David. Aber warum definieren Sie dann nicht jede Methode als statische Methode, da sie auch für Instanzen funktioniert? Gibt es irgendwelche Nachteile dabei?
Curious2learn
4
@ Curious2learn: Nein, mit statischen Methoden haben Sie keinen Zugriff auf die Instanz: Die Instanz wird mit Ausnahme ihrer Klasse ignoriert.
Felix Kling
4
Dieses Argument trifft auf Java zu, wo Funktionen nicht von selbst leben können, sondern immer im Kontext einer Klasse definiert werden. In Python können Sie jedoch Funktionen und statische Klassenfunktionen haben. Diese Antwort zeigt nicht wirklich, warum eine statische Methode anstelle einer Methode gewählt werden sollte, die nicht zu einer Klasse gehört.
Extraneon
1
@extraneon - das ist eher eine Frage der organisatorischen Präferenzen des Codes; Mit statischen Methoden hat man die zusätzliche Option.
Charles Duffy
@ Felix - Danke. Dies verdeutlicht, warum nicht jede Methode eine statische Methode sein sollte.
Curious2learn
2

Die Alternativen zu a staticmethodsind: classmethod, instancemethod, und function. Wenn Sie nicht wissen, um was es sich handelt, scrollen Sie zum letzten Abschnitt. Ob a staticmethodbesser ist als eine dieser Alternativen, hängt davon ab, zu welchem ​​Zweck es geschrieben wurde.

Vorteile der statischen Python-Methode

  • Wenn Sie keinen Zugriff auf die Attribute oder Methoden der Klasse oder Instanz benötigen, staticmethodist a besser als a classmethododer instancemethod. Auf diese Weise wird (vom @staticmethodDekorateur) klar, dass der Status der Klasse und der Instanz nicht gelesen oder geändert wird. Die Verwendung von a functionmacht diese Unterscheidung jedoch noch deutlicher (siehe Nachteile).
  • Die Rufsignatur von a staticmethodist die gleiche wie die von a classmethododer instancemethod, nämlich <instance>.<method>(<arguments>). Daher kann es leicht durch eines der drei ersetzt werden, wenn dies später oder in einer abgeleiteten Klasse benötigt wird. Mit einem einfachen kann man das nicht machen function.
  • A staticmethodkann anstelle von a verwendet werden function, um zu verdeutlichen, dass es subjektiv zu einer Klasse gehört, und um Namespace-Konflikte zu vermeiden.

Nachteile der statischen Python-Methode

  • Es kann nicht auf Attribute oder Methoden der Instanz oder Klasse zugreifen.
  • Die Rufsignatur von a staticmethodist die gleiche wie die von a classmethododer instancemethod. Dies maskiert die Tatsache, dass das staticmethodObjekt keine Objektinformationen liest oder ändert. Dies erschwert das Lesen von Code. Warum nicht einfach ein verwenden function?
  • A staticmethodist schwer wiederzuverwenden, wenn Sie es jemals von außerhalb der Klasse / Instanz aufrufen müssen, in der es definiert wurde. Wenn die Möglichkeit einer Wiederverwendung besteht, functionist a die bessere Wahl.
  • Das staticmethodwird selten verwendet, daher kann es etwas länger dauern, bis Benutzer Code lesen, der einen enthält.

Alternativen zu einer statischen Methode in Python

Um die Vorteile der zu diskutieren staticmethod, müssen wir wissen, welche Alternativen es gibt und wie sie sich voneinander unterscheiden.

  • Der staticmethodgehört zu einer Klasse, kann jedoch nicht auf Instanz- oder Klasseninformationen zugreifen oder diese ändern.

Es gibt drei Alternativen dazu:

  • Der classmethodhat Zugriff auf die Klasse des Anrufers.
  • Der instancemethodhat Zugriff auf die Instanz des Aufrufers und seine Klasse.
  • Das functionhat nichts mit Unterricht zu tun. Es ist der Fähigkeit am nächsten staticmethod.

So sieht das im Code aus:

# function
# has nothing to do with a class
def make_cat_noise(asker_name):
    print('Hi %s, mieets mieets!' % asker_name)

# Yey, we can make cat noises before we've even defined what a cat is!
make_cat_noise('JOey')  # just a function

class Cat:
    number_of_legs = 4

    # special instance method __init__
    def __init__(self, name):
        self.name = name

    # instancemethod
    # the instance (e.g. Cat('Kitty')) is passed as the first method argument
    def tell_me_about_this_animal(self, asker_name):
        print('Hi %s, This cat has %d legs and is called %s'
              % (asker_name, self.number_of_legs, self.name))

    # classmethod
    # the class (e.g. Cat) is passed as the first method argument
    # by convention we call that argument cls
    @classmethod
    def tell_me_about_cats(cls, asker_name):
        print("Hi %s, cats have %d legs."
              % (asker_name, cls.number_of_legs))
        # cls.name  # AttributeError because only the instance has .name
        # self.name  # NameError because self isn't defined in this namespace

    # staticmethod
    # no information about the class or the instance is passed to the method
    @staticmethod
    def make_noise(asker_name):
        print('Hi %s, meooow!' % asker_name)
        # class and instance are not accessible from here

# one more time for fun!
make_cat_noise('JOey')  # just a function

# We just need the class to call a classmethod or staticmethod:
Cat.make_noise('JOey')  # staticmethod
Cat.tell_me_about_cats('JOey')  # classmethod
# Cat.tell_me_about_this_animal('JOey')  # instancemethod -> TypeError

# With an instance we can use instancemethod, classmethod or staticmethod
mycat = Cat('Kitty')  # mycat is an instance of the class Cat
mycat.make_noise('JOey')  # staticmethod
mycat.tell_me_about_cats('JOey')  # classmethod
mycat.tell_me_about_this_animal('JOey')  # instancemethod
Joooeey
quelle
1

Weil Namespace-Funktionen nett sind (wie bereits erwähnt):

  1. Wenn ich explizit auf Methoden eingehen möchte, die den Status des Objekts nicht ändern, verwende ich statische Methoden. Dies entmutigt die Mitarbeiter meines Teams, die Attribute des Objekts in diesen Methoden zu ändern.

  2. Wenn ich wirklich faulen Code umgestalte, versuche ich zunächst, so viele Methoden @staticmethodwie möglich zu erstellen . Dadurch kann ich diese Methoden dann in eine Klasse extrahieren - obwohl ich damit einverstanden bin, ist dies selten etwas, das ich verwende, es hat sich jedoch einige Male als hilfreich erwiesen.

vlad-ardelean
quelle
1

Nach meiner Einschätzung gibt es keinen einzigen Leistungsvorteil der Verwendung von @staticmethods im Vergleich zur Definition der Funktion außerhalb und getrennt von der Klasse, von der es sonst wäre @staticmethod.

Das einzige, was ich sagen würde, um ihre Existenz zu rechtfertigen, ist Bequemlichkeit. Statische Methoden sind in anderen gängigen Programmiersprachen üblich. Warum also nicht Python? Wenn Sie eine Funktion mit einem Verhalten erstellen möchten, das sehr eng mit der Klasse verknüpft ist, für die Sie sie erstellen, aber nicht auf die internen Daten einer Instanz der Klasse zugreifen / diese ändern, so dass die Konzeptualisierung als typisch gerechtfertigt ist Methode dieser Klasse schlagen @staticmethodSie dann ein darüber und jeder, der Ihren Code liest, wird sofort viel über die Natur der Methode und ihre Beziehung zur Klasse lernen.

Eine Sache, die ich gelegentlich gerne mache, ist das Platzieren von Funktionen, die meine Klasse intern häufig verwendet, in privaten @staticmethods. Auf diese Weise überfalle ich die von meinem Modul bereitgestellte API nicht mit Methoden, die niemand, der mein Modul verwendet, jemals sehen müsste, geschweige denn verwenden würde.

Garrett Gutierrez
quelle
0

Statische Methoden haben in Python fast keinen Grund. Sie verwenden entweder Instanzmethoden oder Klassenmethoden.

def method(self, args):
    self.member = something

@classmethod
def method(cls, args):
    cls.member = something

@staticmethod
def method(args):
    MyClass.member = something
    # The above isn't really working
    # if you have a subclass
Georg Schölly
quelle
Du hast "fast" gesagt. Gibt es einen Ort, an dem sie besser sein können als die Alternativen?
Javier
@Javier: Ich kann mir keine vorstellen, aber es gibt wahrscheinlich eine. Warum sollte diese Methode sonst in die Python-Bibliothek aufgenommen werden?
Georg Schölly
1
@Javier, @Georg: Sie haben großes Vertrauen, dass der Python-Korpus keine Cruft hat.
Charles Merriam
-1: Diese Antwort enthält keinen Anwendungsfall staticmethododer eine Erklärung dafür, was a classmethodist oder warum und wie es "besser" ist als statische.
MestreLion
@CharlesMerriam: Natürlich werden statische Methoden verwendet, sonst wäre sie in Python 3 (wo der größte Teil der alten Cruft entfernt wurde) gelöscht oder veraltet. In Dokumenten gibt es kein einziges Wort dagegen staticmethod, das Ihre Behauptung stützt, es sei Cruft, oder Georgs Behauptung, classmethoddie stattdessen verwendet werden sollte.
MestreLion