Ist es möglich, statische Klassenvariablen oder Methoden in Python zu haben? Welche Syntax ist dazu erforderlich?
Variablen, die innerhalb der Klassendefinition, jedoch nicht innerhalb einer Methode deklariert sind, sind Klassen- oder statische Variablen:
>>> class MyClass:
... i = 3
...
>>> MyClass.i
3
Wie @ millerdev hervorhebt , wird dadurch eine i
Variable auf Klassenebene erstellt , die sich jedoch von allen i
Variablen auf Instanzebene unterscheidet
>>> m = MyClass()
>>> m.i = 4
>>> MyClass.i, m.i
>>> (3, 4)
Dies unterscheidet sich von C ++ und Java, jedoch nicht von C #, bei dem auf ein statisches Mitglied nicht über einen Verweis auf eine Instanz zugegriffen werden kann.
Lesen Sie, was das Python-Tutorial zum Thema Klassen und Klassenobjekte zu sagen hat .
@Steve Johnson hat bereits zu statischen Methoden geantwortet , die auch unter "Integrierte Funktionen" in der Python-Bibliotheksreferenz dokumentiert sind .
class C:
@staticmethod
def f(arg1, arg2, ...): ...
@beidy empfiehlt Klassenmethoden gegenüber statischen Methoden, da die Methode dann den Klassentyp als erstes Argument empfängt, aber ich bin immer noch ein wenig verwirrt über die Vorteile dieses Ansatzes gegenüber statischen Methoden. Wenn Sie auch sind, dann ist es wahrscheinlich egal.
@classmethod
über@staticmethod
AFAIK ist , dass Sie immer den Namen der Klasse bekommen die Methode aufgerufen wurde auf, auch wenn es sich um eine Unterklasse ist. Einer statischen Methode fehlen diese Informationen, sodass sie beispielsweise keine überschriebene Methode aufrufen kann.const.py
mitPI = 3.14
und Sie können es überall importieren.from const import PI
i = 3
ist nicht eine statische Variable, sondern um ein Klassenattribut. Da es sich von einem Attribut auf Instanzebenei
unterscheidet , verhält es sich in anderen Sprachen nicht wie eine statische Variable. Siehe millerdev Antwort , Yann Antwort , und meine Antwort unten.i
(statische Variable) im Speicher sein, selbst wenn ich Hunderte von Instanzen dieser Klasse erstelle?@Blair Conrad sagte, dass statische Variablen, die in der Klassendefinition, aber nicht in einer Methode deklariert sind, Klassen- oder "statische" Variablen sind:
Hier gibt es ein paar Fallstricke. Fortsetzung des obigen Beispiels:
Beachten Sie, dass die Instanzvariable
t.i
nicht mehr mit der "statischen" Klassenvariablen synchronisiert wurde, als das Attributi
direkt aktiviert wurdet
. Dies liegt darani
, dass innerhalb dest
Namespace, der sich vomTest
Namespace unterscheidet, neu gebunden wurde . Wenn Sie den Wert einer "statischen" Variablen ändern möchten, müssen Sie ihn innerhalb des Bereichs (oder Objekts) ändern, in dem er ursprünglich definiert wurde. Ich habe "statisch" in Anführungszeichen gesetzt, weil Python nicht wirklich statische Variablen in dem Sinne hat, wie es C ++ und Java tun.Obwohl es nichts Spezifisches über statische Variablen oder Methoden aussagt, enthält das Python-Lernprogramm einige relevante Informationen zu Klassen und Klassenobjekten .
@Steve Johnson antwortete auch in Bezug auf statische Methoden, die ebenfalls unter "Integrierte Funktionen" in der Python-Bibliotheksreferenz dokumentiert sind.
@beid erwähnte auch die Klassenmethode, die der statischen Methode ähnelt. Das erste Argument einer Klassenmethode ist das Klassenobjekt. Beispiel:
quelle
class Test(object):
,_i = 3
,@property
,def i(self)
,return type(self)._i
,@i.setter
,def i(self,val):
,type(self)._i = val
. Jetzt können Sie tunx = Test()
,x.i = 12
,assert x.i == Test.i
.Statische und Klassenmethoden
Wie die anderen Antworten angemerkt haben, können statische und Klassenmethoden mit den eingebauten Dekoratoren leicht durchgeführt werden:
Wie üblich ist das erste Argument
MyMethod()
an an das Klasseninstanzobjekt gebunden. Im Gegensatz zu dem ersten ArgumenteMyClassMethod()
wird auf das Klassenobjekt gebunden selbst (zB in diesem FallTest
). ZumMyStaticMethod()
keines der Argumente ist gebunden, und Argumente sind optional."Statische Variablen"
Die Implementierung von "statischen Variablen" (also veränderbare statische Variablen, wenn dies kein Widerspruch ist ...) ist jedoch nicht so einfach. Wie millerdev in seiner Antwort hervorhob , besteht das Problem darin, dass Pythons Klassenattribute keine wirklich "statischen Variablen" sind. Erwägen:
Dies liegt daran, dass die Zeile
x.i = 12
ein neues Instanzattribut hinzugefügt hati
,x
anstatt den Wert desTest
Klassenattributs zu änderni
.Das teilweise erwartete Verhalten statischer Variablen, dh das Synchronisieren des Attributs zwischen mehreren Instanzen (jedoch nicht mit der Klasse selbst; siehe "gotcha" unten), kann erreicht werden, indem das Klassenattribut in eine Eigenschaft umgewandelt wird:
Jetzt können Sie tun:
Die statische Variable bleibt nun zwischen allen Klasseninstanzen synchron .
(HINWEIS: Das heißt, es sei denn, eine Klasseninstanz beschließt, ihre eigene Version von zu definieren
_i
! Aber wenn sich jemand dafür entscheidet, verdient er das, was er bekommt, nicht wahr ???)Beachten Sie, dass es sich technisch gesehen
i
immer noch überhaupt nicht um eine 'statische Variable' handelt. es ist einproperty
, was eine spezielle Art von Deskriptor ist. Dasproperty
Verhalten entspricht jetzt jedoch einer (veränderlichen) statischen Variablen, die über alle Klasseninstanzen hinweg synchronisiert wird.Unveränderliche "statische Variablen"
Lassen Sie für ein unveränderliches Verhalten statischer Variablen einfach den
property
Setter weg:Wenn Sie nun versuchen, das Instanzattribut
i
festzulegen, wird Folgendes zurückgegebenAttributeError
:Ein Gotcha, dessen man sich bewusst sein sollte
Beachten Sie, dass die oben genannten Methoden nur mit Instanzen Ihrer Klasse funktionieren - sie funktionieren nicht , wenn Sie die Klasse selbst verwenden . Also zum Beispiel:
Die Zeile
assert Test.i == x.i
erzeugt einen Fehler, da dasi
Attribut vonTest
undx
zwei verschiedene Objekte sind.Viele Leute werden dies überraschend finden. Dies sollte jedoch nicht der Fall sein. Wenn wir zurückgehen und unsere
Test
Klassendefinition (die zweite Version) überprüfen , beachten wir diese Zeile:Das Mitglied
i
vonTest
muss eindeutig einproperty
Objekt sein. Dies ist der Objekttyp, der von derproperty
Funktion zurückgegeben wird.Wenn Sie das oben Genannte verwirrend finden, denken Sie höchstwahrscheinlich immer noch aus der Perspektive anderer Sprachen (z. B. Java oder C ++) darüber nach. Du solltest das studieren gehen
property
Objekt untersuchen, über die Reihenfolge, in der Python-Attribute zurückgegeben werden, das Deskriptorprotokoll und die Methodenauflösungsreihenfolge (MRO).Ich präsentiere eine Lösung für das obige 'Gotcha' unten; Ich würde jedoch mit Nachdruck vorschlagen, dass Sie nicht versuchen, Folgendes zu tun, bis Sie zumindest gründlich verstanden haben, warum
assert Test.i = x.i
ein Fehler verursacht wird.ECHTE, TATSÄCHLICHE statische Variablen -
Test.i == x.i
Ich präsentiere die (Python 3) -Lösung unten nur zu Informationszwecken. Ich unterstütze es nicht als "gute Lösung". Ich habe meine Zweifel, ob die Emulation des statischen Variablenverhaltens anderer Sprachen in Python jemals wirklich notwendig ist. Unabhängig davon, ob es tatsächlich nützlich ist, sollte das Folgende zum besseren Verständnis der Funktionsweise von Python beitragen.
UPDATE: Dieser Versuch ist wirklich ziemlich schrecklich ; Wenn Sie darauf bestehen, so etwas zu tun (Hinweis: Bitte nicht; Python ist eine sehr elegante Sprache, und es ist einfach nicht notwendig, sich wie eine andere Sprache zu verhalten), verwenden Sie stattdessen den Code in Ethan Furmans Antwort .
Emulieren des Verhaltens statischer Variablen anderer Sprachen mithilfe einer Metaklasse
Eine Metaklasse ist die Klasse einer Klasse. Die Standard-Metaklasse für alle Klassen in Python (dh die "New Style" -Klassen nach Python 2.3, glaube ich) ist
type
. Zum Beispiel:Sie können Ihre eigene Metaklasse jedoch folgendermaßen definieren:
Und wenden Sie es wie folgt auf Ihre eigene Klasse an (nur Python 3):
Unten ist eine von mir erstellte Metaklasse, die versucht, das Verhalten "statischer Variablen" anderer Sprachen zu emulieren. Grundsätzlich wird der Standard-Getter, -Setter und -Löscher durch Versionen ersetzt, die prüfen, ob das angeforderte Attribut eine "statische Variable" ist.
Ein Katalog der "statischen Variablen" wird im
StaticVarMeta.statics
Attribut gespeichert . Es wird zunächst versucht, alle Attributanforderungen mithilfe einer Ersatzauflösungsreihenfolge aufzulösen. Ich habe dies die "statische Auflösungsreihenfolge" oder "SRO" genannt. Dies erfolgt durch Suchen nach dem angeforderten Attribut in der Menge der "statischen Variablen" für eine bestimmte Klasse (oder ihre übergeordneten Klassen). Wenn das Attribut nicht in der "SRO" angezeigt wird, greift die Klasse auf das Standardattribut get / set / delete zurück (dh "MRO").quelle
Test
(bevor Sie es zum Instanziieren von Instanzen verwenden), als im Bereich der Metaprogrammierung befindlich ansehen ? Zum Beispiel ändern Sie das Klassenverhalten, indem Sie dies tunTest.i = 0
(hier zerstören Sie einfach das Eigenschaftsobjekt vollständig). Ich denke, der "Eigenschaftsmechanismus" wird nur beim Eigenschaftszugriff auf Instanzen einer Klasse aktiviert (es sei denn, Sie ändern das zugrunde liegende Verhalten möglicherweise mithilfe einer Metaklasse als Zwischenstufe). Übrigens, bitte beenden Sie diese Antwort :-)Sie können Klassen auch im laufenden Betrieb Klassenvariablen hinzufügen
Und Klasseninstanzen können Klassenvariablen ändern
quelle
Persönlich würde ich eine Klassenmethode verwenden, wenn ich eine statische Methode benötigte. Hauptsächlich, weil ich die Klasse als Argument bekomme.
oder verwenden Sie einen Dekorateur
Für statische Eigenschaften. Es ist an der Zeit, eine Python-Definition nachzuschlagen. Die Variable kann sich jederzeit ändern. Es gibt zwei Arten von ihnen, die veränderlich und unveränderlich sind. Außerdem gibt es Klassenattribute und Instanzattribute. Nichts wie statische Attribute im Sinne von Java & C ++
Warum statische Methode im pythonischen Sinne verwenden, wenn sie keinerlei Beziehung zur Klasse hat? Wenn ich Sie wäre, würde ich entweder die Klassenmethode verwenden oder die Methode unabhängig von der Klasse definieren.
quelle
Eine besondere Anmerkung zu statischen Eigenschaften und Instanzeigenschaften, die im folgenden Beispiel gezeigt wird:
Dies bedeutet, dass vor dem Zuweisen des Werts zur Instanzeigenschaft der statische Wert verwendet wird, wenn wir versuchen, über die Instanz auf die Eigenschaft zuzugreifen. Jede in der Python-Klasse deklarierte Eigenschaft verfügt immer über einen statischen Speicherplatz .
quelle
Statische Methoden in Python werden aufgerufen Klassenmethoden bezeichnet . Schauen Sie sich den folgenden Code an
Beachten Sie, dass beim Aufrufen der Methode myInstanceMethod eine Fehlermeldung angezeigt wird. Dies liegt daran, dass die Methode für eine Instanz dieser Klasse aufgerufen werden muss. Die Methode myStaticMethod wird mit der Methode als Klassenmethode festgelegt Decorator @classmethod festgelegt .
Nur für Tritte und Kichern könnten wir myInstanceMethod für die Klasse aufrufen, indem wir eine Instanz der Klasse übergeben, wie folgt :
quelle
@staticmethod
;@classmethod
ist (offensichtlich) für Klassenmethoden (die hauptsächlich zur Verwendung als alternative Konstruktoren vorgesehen sind, aber zur Not als statische Methoden dienen können, die zufällig einen Verweis auf die Klasse erhalten, durch die sie aufgerufen wurden).Wenn Sie eine Elementvariable außerhalb einer Elementmethode definieren, kann die Variable je nach Ausdruck der Variablen entweder statisch oder nicht statisch sein.
Zum Beispiel:
Die Ergebnisse sind
quelle
Es ist möglich zu haben
static
Klassenvariablen , aber die Mühe lohnt sich wahrscheinlich nicht.Hier ist ein in Python 3 geschriebener Proof-of-Concept. Wenn eines der genauen Details falsch ist, kann der Code so angepasst werden, dass er genau dem entspricht, was Sie mit a meinen
static variable
:und in Gebrauch:
und einige Tests:
quelle
Sie können eine Klasse auch mithilfe der Metaklasse als statisch erzwingen.
Wenn Sie dann versehentlich versuchen, MyClass zu initialisieren, erhalten Sie einen StaticClassError.
quelle
__new__
ihrer Eltern aufzurufen ...Ein sehr interessanter Punkt bei Pythons Attributsuche ist, dass damit " virtuelle Variablen" erstellt werden können:
Normalerweise gibt es keine Zuordnungen zu diesen, nachdem sie erstellt wurden. Beachten Sie, dass die Suche verwendet wird,
self
da der Wert zwarlabel
statisch in dem Sinne ist, dass er keiner bestimmten Instanz zugeordnet ist, der Wert jedoch immer noch von der (Klasse der) Instanz abhängt.quelle
In Bezug auf diese Antwort können Sie für eine konstante statische Variable einen Deskriptor verwenden. Hier ist ein Beispiel:
ergebend ...
Sie können jederzeit eine Ausnahme auslösen, wenn
pass
es nicht Ihre Sache ist , den Einstellwert ( oben) stillschweigend zu ignorieren . Wenn Sie nach einer statischen Klassenvariablen im C ++ - Java-Stil suchen:Weitere Informationen zu Deskriptoren finden Sie in dieser Antwort und in den offiziellen HOWTO- Dokumenten .
quelle
@property
, was mit einem Deskriptor identisch ist, aber es ist viel weniger Code.Absolut Ja, Python selbst hat kein explizites statisches Datenelement, aber wir können dies tun
Ausgabe
Erläuterung
quelle
Ja, es ist definitiv möglich, statische Variablen und Methoden in Python zu schreiben.
Statische Variablen: Auf Klassenebene deklarierte Variablen werden als statische Variablen bezeichnet, auf die direkt über den Klassennamen zugegriffen werden kann.
Instanzvariablen: Variablen, die von einer Instanz einer Klasse verknüpft sind und auf die zugegriffen wird, sind Instanzvariablen.
Statische Methoden: Ähnlich wie bei Variablen kann auf statische Methoden direkt über den Klassennamen zugegriffen werden. Sie müssen keine Instanz erstellen.
Beachten Sie jedoch, dass eine statische Methode in Python keine nicht statische Methode aufrufen kann.
quelle
Um mögliche Verwirrung zu vermeiden, möchte ich statische Variablen und unveränderliche Objekte gegenüberstellen.
Einige primitive Objekttypen wie Ganzzahlen, Gleitkommazahlen, Zeichenfolgen und Touple sind in Python unveränderlich. Dies bedeutet, dass sich das Objekt, auf das mit einem bestimmten Namen verwiesen wird, nicht ändern kann, wenn es von einem der oben genannten Objekttypen ist. Der Name kann einem anderen Objekt zugewiesen werden, das Objekt selbst darf jedoch nicht geändert werden.
Wenn Sie eine Variable statisch machen, gehen Sie noch einen Schritt weiter, indem Sie nicht zulassen, dass der Variablenname auf ein anderes Objekt als das zeigt, auf das er derzeit verweist. (Hinweis: Dies ist ein allgemeines Softwarekonzept und nicht spezifisch für Python. Informationen zum Implementieren von Statik in Python finden Sie in den Beiträgen anderer.)
quelle
Der beste Weg, den ich gefunden habe, ist, eine andere Klasse zu verwenden. Sie können ein Objekt erstellen und es dann für andere Objekte verwenden.
Mit dem obigen Beispiel habe ich eine Klasse mit dem Namen erstellt
staticFlag
.Diese Klasse sollte die statische Variable
__success
(Private Static Var) darstellen.tryIt
Klasse repräsentiert die reguläre Klasse, die wir verwenden müssen.Jetzt habe ich ein Objekt für eine Flagge gemacht (
staticFlag
). Dieses Flag wird als Referenz auf alle regulären Objekte gesendet.Alle diese Objekte werden der Liste hinzugefügt
tryArr
.Dieses Skript Ergebnisse:
quelle
Statische Variablen in Class Factory Python3.6
Für alle, die eine Klassenfactory mit Python3.6 oder höher verwenden , verwenden Sie das
nonlocal
Schlüsselwort, um sie dem Bereich / Kontext der Klasse hinzuzufügen, die wie folgt erstellt wird:quelle
hasattr(SomeClass, 'x')
istFalse
. Ich bezweifle, dass dies überhaupt jemand mit einer statischen Variablen meint.some_var
unveränderlich und statisch definiert, oder nicht? Was hat der externe Getter-Zugriff damit zu tun, dass eine Variable statisch ist oder nicht? Ich habe jetzt so viele Fragen. würde gerne einige Antworten hören, wenn Sie die Zeit bekommen.some_var
oben überhaupt kein Klassenmitglied. In Python kann von außerhalb der Klasse auf alle Klassenmitglieder zugegriffen werden.nonlocal
Keywoard "stößt" den Bereich der Variablen an. Der Bereich einer Klassenkörperdefinition ist unabhängig von dem Bereich, in dem sie sich befindet, wenn Sie sagennonlocal some_var
, dass lediglich ein nicht lokaler ( sprich : NICHT im Bereich der Klassendefinition) Namensreferenz auf ein anderes benanntes Objekt erstellt wird. Daher wird es nicht an die Klassendefinition angehängt, da es nicht im Bereich des Klassenkörpers enthalten ist.Das ist also wahrscheinlich ein Hack, aber ich habe
eval(str)
in Python 3 ein statisches Objekt erhalten, eine Art Widerspruch.Es gibt eine Records.py-Datei, in der nur
class
Objekte mit statischen Methoden und Konstruktoren definiert sind, die einige Argumente speichern. Dann muss ich aus einer anderen .py-Dateiimport Records
jedes Objekt dynamisch auswählen und es dann bei Bedarf entsprechend der Art der eingelesenen Daten instanziieren.Also, wo
object_name = 'RecordOne'
oder den Klassennamen rufe ich aufcur_type = eval(object_name)
und dann, um ihn zu instanziieren, tuncur_inst = cur_type(args)
Sie dies. Bevor Sie jedoch instanziieren, können Sie statische Methoden aufrufen,cur_type.getName()
beispielsweise wie eine abstrakte Basisklassenimplementierung oder was auch immer das Ziel ist. Im Backend ist es jedoch wahrscheinlich in Python instanziiert und nicht wirklich statisch, da eval ein Objekt zurückgibt, das instanziiert worden sein muss und ein statisches Verhalten ergibt.quelle
Sie können eine Liste oder ein Wörterbuch verwenden, um "statisches Verhalten" zwischen Instanzen zu erhalten.
quelle
Wenn Sie versuchen, eine statische Variable freizugeben, um sie beispielsweise für andere Instanzen zu erhöhen, funktioniert so etwas wie dieses Skript einwandfrei:
quelle