Wie erstelle ich statische Klassenvariablen oder Methoden in Python?
Antworten
Zu viele Anzeigen?Eine Besonderheit ist bei statischen Eigenschaften und Instanzeigenschaften zu beachten, wie im folgenden Beispiel gezeigt:
class my_cls:
my_prop = 0
#static property
print my_cls.my_prop #--> 0
#assign value to static property
my_cls.my_prop = 1
print my_cls.my_prop #--> 1
#access static property thru' instance
my_inst = my_cls()
print my_inst.my_prop #--> 1
#instance property is different from static property
#after being assigned a value
my_inst.my_prop = 2
print my_cls.my_prop #--> 1
print my_inst.my_prop #--> 2
Das bedeutet, dass der statische Wert verwendet wird, bevor der Wert der Instanzeigenschaft zugewiesen wird, wenn wir versuchen, auf die Eigenschaft über die Instanz zuzugreifen. Jede in einer Python-Klasse deklarierte Eigenschaft hat immer einen statischen Platz im Speicher .
Statische Methoden in Python heißen Klassenmethode s. Werfen Sie einen Blick auf den folgenden Code
class MyClass:
def myInstanceMethod(self):
print 'output from an instance method'
@classmethod
def myStaticMethod(cls):
print 'output from a static method'
>>> MyClass.myInstanceMethod()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method myInstanceMethod() must be called [...]
>>> MyClass.myStaticMethod()
output from a static method
Beachten Sie, dass wir beim Aufruf der Methode myInstanceMethod erhalten wir einen Fehler. Das liegt daran, dass diese Methode auf einer Instanz dieser Klasse aufgerufen werden muss. Die Methode myStaticMethod wird als Klassenmethode mit der Methode Tapezierer @classmethod .
Nur so zum Spaß könnten wir anrufen myInstanceMethod auf die Klasse anwenden, indem Sie eine Instanz der Klasse übergeben, etwa so:
>>> MyClass.myInstanceMethod(MyClass())
output from an instance method
Es ist möglich, Folgendes zu haben static
Klassenvariablen, aber wahrscheinlich lohnt sich der Aufwand nicht.
Hier ist ein Proof-of-Concept, das in Python 3 geschrieben wurde - wenn einige der genauen Details falsch sind, kann der Code so angepasst werden, dass er genau dem entspricht, was Sie mit einem static variable
:
class Static:
def __init__(self, value, doc=None):
self.deleted = False
self.value = value
self.__doc__ = doc
def __get__(self, inst, cls=None):
if self.deleted:
raise AttributeError('Attribute not set')
return self.value
def __set__(self, inst, value):
self.deleted = False
self.value = value
def __delete__(self, inst):
self.deleted = True
class StaticType(type):
def __delattr__(cls, name):
obj = cls.__dict__.get(name)
if isinstance(obj, Static):
obj.__delete__(name)
else:
super(StaticType, cls).__delattr__(name)
def __getattribute__(cls, *args):
obj = super(StaticType, cls).__getattribute__(*args)
if isinstance(obj, Static):
obj = obj.__get__(cls, cls.__class__)
return obj
def __setattr__(cls, name, val):
# check if object already exists
obj = cls.__dict__.get(name)
if isinstance(obj, Static):
obj.__set__(name, val)
else:
super(StaticType, cls).__setattr__(name, val)
und im Einsatz:
class MyStatic(metaclass=StaticType):
"""
Testing static vars
"""
a = Static(9)
b = Static(12)
c = 3
class YourStatic(MyStatic):
d = Static('woo hoo')
e = Static('doo wop')
und einige Tests:
ms1 = MyStatic()
ms2 = MyStatic()
ms3 = MyStatic()
assert ms1.a == ms2.a == ms3.a == MyStatic.a
assert ms1.b == ms2.b == ms3.b == MyStatic.b
assert ms1.c == ms2.c == ms3.c == MyStatic.c
ms1.a = 77
assert ms1.a == ms2.a == ms3.a == MyStatic.a
ms2.b = 99
assert ms1.b == ms2.b == ms3.b == MyStatic.b
MyStatic.a = 101
assert ms1.a == ms2.a == ms3.a == MyStatic.a
MyStatic.b = 139
assert ms1.b == ms2.b == ms3.b == MyStatic.b
del MyStatic.b
for inst in (ms1, ms2, ms3):
try:
getattr(inst, 'b')
except AttributeError:
pass
else:
print('AttributeError not raised on %r' % attr)
ms1.c = 13
ms2.c = 17
ms3.c = 19
assert ms1.c == 13
assert ms2.c == 17
assert ms3.c == 19
MyStatic.c = 43
assert ms1.c == 13
assert ms2.c == 17
assert ms3.c == 19
ys1 = YourStatic()
ys2 = YourStatic()
ys3 = YourStatic()
MyStatic.b = 'burgler'
assert ys1.a == ys2.a == ys3.a == YourStatic.a == MyStatic.a
assert ys1.b == ys2.b == ys3.b == YourStatic.b == MyStatic.b
assert ys1.d == ys2.d == ys3.d == YourStatic.d
assert ys1.e == ys2.e == ys3.e == YourStatic.e
ys1.a = 'blah'
assert ys1.a == ys2.a == ys3.a == YourStatic.a == MyStatic.a
ys2.b = 'kelp'
assert ys1.b == ys2.b == ys3.b == YourStatic.b == MyStatic.b
ys1.d = 'fee'
assert ys1.d == ys2.d == ys3.d == YourStatic.d
ys2.e = 'fie'
assert ys1.e == ys2.e == ys3.e == YourStatic.e
MyStatic.a = 'aargh'
assert ys1.a == ys2.a == ys3.a == YourStatic.a == MyStatic.a
Wenn eine Mitgliedsvariable außerhalb einer Mitgliedsmethode definiert wird, kann die Variable entweder statisch oder nicht statisch sein, je nachdem, wie die Variable ausgedrückt wird.
- CLASSNAME.var ist eine statische Variable
- INSTANCENAME.var ist keine statische Variable.
- self.var innerhalb der Klasse ist keine statische Variable.
- var innerhalb der Klassenfunktion ist nicht definiert.
Zum Beispiel:
#!/usr/bin/python
class A:
var=1
def printvar(self):
print "self.var is %d" % self.var
print "A.var is %d" % A.var
a = A()
a.var = 2
a.printvar()
A.var = 3
a.printvar()
Die Ergebnisse sind
self.var is 2
A.var is 1
self.var is 2
A.var is 3
@dataclass-Definitionen liefern Namen auf Klassenebene, die zur Definition der Instanzvariablen und der Initialisierungsmethode verwendet werden, __init__()
. Wenn Sie eine Variable auf Klassenebene in @dataclass
sollten Sie typing.ClassVar
Typ-Hinweis. Die Website ClassVar
Die Parameter des Typs definieren den Typ der Variablen auf Klassenebene.
from typing import ClassVar
from dataclasses import dataclass
@dataclass
class Test:
i: ClassVar[int] = 10
x: int
y: int
def __repr__(self):
return f"Test({self.x=}, {self.y=}, {Test.i=})"
Beispiele für den Gebrauch:
> test1 = Test(5, 6)
> test2 = Test(10, 11)
> test1
Test(self.x=5, self.y=6, Test.i=10)
> test2
Test(self.x=10, self.y=11, Test.i=10)