Wie deklariere ich eine Konstante in Python?
In Java machen wir:
public static final String CONST_NAME = "Name";
Wie deklariere ich eine Konstante in Python?
In Java machen wir:
public static final String CONST_NAME = "Name";
Hier ist eine Implementierung einer "Constants" Klasse, die Instanzen mit schreibgeschützten (konstanten) Attributen erstellt. Z.B. kann man Nums.PI
verwenden, um einen Wert abzurufen, der als 3.14159
initialisiert wurde, und Nums.PI = 22
wirft eine Ausnahme.
# ---------- Constants.py ----------
class Constants(object):
"""
Erstelle Objekte mit schreibgeschützten (konstanten) Attributen.
Beispiel:
Nums = Constants(ONE=1, PI=3.14159, DefaultWidth=100.0)
print 10 + Nums.PI
print '----- Folgende Zeile führt absichtlich zu einem ValueError -----'
Nums.PI = 22
"""
def __init__(self, *args, **kwargs):
self._d = dict(*args, **kwargs)
def __iter__(self):
return iter(self._d)
def __len__(self):
return len(self._d)
# HINWEIS: Dies wird nur aufgerufen, wenn das Attribut fehlt.
# Es stört also nicht bei 'self._d' usw.
def __getattr__(self, name):
return self._d[name]
# GEHT DAVON AUS, dass '_...' Attribut in Ordnung ist zum Setzen. Braucht man das zur Initialisierung von 'self._d' usw.
# Wenn als Schlüssel verwendet, sind sie nicht konstant.
def __setattr__(self, name, value):
if (name[0] == '_'):
super(Constants, self).__setattr__(name, value)
else:
raise ValueError("setattr während gesperrt", self)
if (__name__ == "__main__"):
# Beispiel für Verwendung.
Nums = Constants(ONE=1, PI=3.14159, DefaultWidth=100.0)
print 10 + Nums.PI
print '----- Folgende Zeile führt absichtlich zu einem ValueError -----'
Nums.PI = 22
Dank an @MikeGraham 's FrozenDict, den ich als Ausgangspunkt verwendet habe. Geändert, so dass anstelle von Nums['ONE']
die Verwendungssyntax Nums.ONE
ist.
Und vielen Dank an @Raufio's Antwort für die Idee, __ setattr __ zu überschreiben.
Oder für eine Implementierung mit mehr Funktionalität, siehe @Hans_meine 's named_constants auf GitHub
Hier ist eine Sammlung von Redewendungen, die ich erstellt habe in einem Versuch, einige der bereits verfügbaren Antworten zu verbessern.
Ich weiß, die Verwendung von Konstanten ist nicht pythonisch, und du solltest dies nicht zu Hause machen!
Aber Python ist so eine dynamische Sprache! Dieses Forum zeigt, wie die Erstellung von Konstrukten möglich ist, die wie Konstanten aussehen und sich anfühlen. Der Hauptzweck dieses Beitrags besteht darin, zu erkunden, was die Sprache ausdrücken kann.
Bitte sei nicht zu streng mit mir :-).
Weitere Details habe ich in einem begleitenden Blog zu diesen Redewendungen geschrieben.
In diesem Beitrag werde ich eine konstante Variable eine konstante Referenz auf Werte (unveränderlich oder anderweitig) nennen. Außerdem sage ich, dass eine Variable einen eingefrorenen Wert hat, wenn sie auf ein veränderliches Objekt verweist, dessen Wert(e) von Client-Code nicht aktualisiert werden können.
Diese Redewendung erzeugt, was wie ein Namensraum von Konstantenvariablen aussieht (auch bekannt als SpaceConstants). Es handelt sich um eine Änderung eines Code-Schnipsels von Alex Martelli, um die Verwendung von Modulobjekten zu vermeiden. Insbesondere verwendet diese Modifikation, was ich eine Klassenfabrik nenne, denn in der Funktion SpaceConstants wird eine Klasse namens SpaceConstants definiert und eine Instanz davon zurückgegeben.
Ich habe die Verwendung von Klassenfabriken erforscht, um ein Design zu implementieren, das in Python einer Richtlinie ähnelt, auf stackoverflow und auch in einem Blogbeitrag.
def SpaceConstants():
def setattr(self, name, value):
if hasattr(self, name):
raise AttributeError(
"Kann Mitglieder nicht neu zuweisen"
)
self.__dict__[name] = value
cls = type('SpaceConstants', (), {
'__setattr__': setattr
})
return cls()
sc = SpaceConstants()
print(sc.x) # wirft "AttributeError: 'SpaceConstants' Objekt hat kein Attribut 'x'"
sc.x = 2 # verknüpfen Attribut x
print(sc.x) # gibt "2" aus
sc.x = 3 # wirft "AttributeError: Kann Mitglieder nicht neu zuweisen"
sc.y = {'name': 'y', 'value': 2} # verknüpfe Attribut y
print(sc.y) # gibt "{'name': 'y', 'value': 2}" aus
sc.y['name'] = 'yprime' # veränderliches Objekt kann geändert werden
print(sc.y) # gibt "{'name': 'yprime', 'value': 2}" aus
sc.y = {} # wirft "AttributeError: Kann Mitglieder nicht neu zuweisen"
Die nächste Redewendung ist eine Modifikation des SpaceConstants, bei der referenzierte veränderliche Objekte eingefroren sind. Diese Implementierung nutzt das, was ich einen gemeinsam genutzten Closure zwischen den Funktionen setattr und getattr aus. Der Wert des veränderlichen Objekts wird kopiert und von der Variablen cache referenziert, die innerhalb des Funktionsshared Closure definiert ist. Es bildet das, was ich eine geschützte Kopie eines veränderlichen Objekts mittels Closure nenne.
Sie müssen vorsichtig sein bei der Verwendung dieser Redewendung, da getattr den Wert von cache mittels einer tiefen Kopie zurückgibt. Diese Operation könnte bei großen Objekten signifikante Leistungseinbußen haben!
from copy import deepcopy
def SpaceFrozenValues():
cache = {}
def setattr(self, name, value):
nonlocal cache
if name in cache:
raise AttributeError(
"Kann Mitglieder nicht neu zuweisen"
)
cache[name] = deepcopy(value)
def getattr(self, name):
nonlocal cache
if name not in cache:
raise AttributeError(
"Objekt hat kein Attribut '{}''".format(name)
)
return deepcopy(cache[name])
cls = type('SpaceFrozenValues', (),{
'__getattr__': getattr,
'__setattr__': setattr
})
return cls()
fv = SpaceFrozenValues()
print(fv.x) # AttributeError: Objekt hat kein Attribut 'x'
fv.x = 2 # verknüpfen Attribut x
print(fv.x) # gibt "2" aus
fv.x = 3 # wirft "AttributeError: Kann Mitglieder nicht neu zuweisen"
fv.y = {'name': 'y', 'value': 2} # verknüpfe Attribut y
print(fv.y) # gibt "{'name': 'y', 'value': 2}" aus
fv.y['name'] = 'yprime' # Sie können versuchen, veränderliche Objekte zu ändern
print(fv.y) # gibt "{'name': 'y', 'value': 2}" aus
fv.y = {} # wirft "AttributeError: Kann Mitglieder nicht neu zuweisen"
Diese Redewendung ist ein unveränderlicher Namensraum von Konstantenvariablen oder ConstantSpace. Es ist eine Kombination der unglaublich einfachen Antwort von Jon Betts in stackoverflow mit einer Klassenfabrik.
def ConstantSpace(**args):
args['__slots__'] = ()
cls = type('ConstantSpace', (), args)
return cls()
cs = ConstantSpace(
x = 2,
y = {'name': 'y', 'value': 2}
)
print(cs.x) # gibt "2" aus
cs.x = 3 # wirft "AttributeError: 'ConstantSpace' Objektattribut 'x' ist schreibgeschützt"
print(cs.y) # gibt "{'name': 'y', 'value': 2}" aus
cs.y['name'] = 'yprime' # veränderliches Objekt kann geändert werden
print(cs.y) # gibt "{'name': 'yprime', 'value': 2}" aus
cs.y = {} # wirft "AttributeError: 'ConstantSpace' Objektattribut 'x' ist schreibgeschützt"
cs.z = 3 # wirft "AttributeError: 'ConstantSpace' Objekt hat kein Attribut 'z'"
Diese Redewendung ist ein unveränderlicher Namensraum von eingefrorenen Variablen oder FrozenSpace. Sie leitet sich vorhergehendes Muster ab, indem jedes Attribut zu einem geschützten Eigentum durch Closure der generierten FrozenSpace-Klasse gemacht wird.
from copy import deepcopy
def FreezeProperty(value):
cache = deepcopy(value)
return property(
lambda self: deepcopy(cache)
)
def FrozenSpace(**args):
args = {k: FreezeProperty(v) for k, v in args.items()}
args['__slots__'] = ()
cls = type('FrozenSpace', (), args)
return cls()
fs = FrozenSpace(
x = 2,
y = {'name': 'y', 'value': 2}
)
print(fs.x) # gibt "2" aus
fs.x = 3 # wirft "AttributeError: 'FrozenSpace' Objektattribut 'x' ist schreibgeschützt"
print(fs.y) # gibt "{'name': 'y', 'value': 2}" aus
fs.y['name'] = 'yprime' # versuchen, veränderliches Objekt zu ändern
print(fs.y) # gibt "{'name': 'y', 'value': 2}" aus
fs.y = {} # wirft "AttributeError: 'FrozenSpace' Objektattribut 'x' ist schreibgeschützt"
fs.z = 3 # wirft "AttributeError: 'FrozenSpace' Objekt hat kein Attribut 'z'"
from enum import Enum
class StringConsts(str,Enum):
ONE='one'
TWO='two'
print(f'Wahrheit ist {StringConsts.ONE=="one"}') #Wahrheit ist True
StringConsts.ONE="one" #Fehler: Kann nicht neu zugewiesen werden
Dieses Mixin aus Enum und str gibt Ihnen die Möglichkeit, setattr nicht neu implementieren zu müssen (durch Enum) und Vergleiche mit anderen str-Objekten durchzuführen (durch str).
Dies könnte http://code.activestate.com/recipes/65207-constants-in-python/?in=user-97991 vollständig veralten lassen.
Ein Tupel qualifiziert sich technisch gesehen als Konstante, da ein Tupel einen Fehler auslösen wird, wenn Sie versuchen, einen seiner Werte zu ändern. Wenn Sie ein Tupel mit einem Wert deklarieren möchten, setzen Sie einfach ein Komma nach seinem einzigen Wert, wie folgt:
my_tuple = (0 """Oder ein anderer Wert""",)
Um den Wert dieser Variablen zu überprüfen, verwenden Sie etwas Ähnliches wie dieses:
if my_tuple[0] == 0:
#Code hier
Wenn Sie versuchen, diesen Wert zu ändern, wird ein Fehler ausgelöst.
Wir können ein Deskriptorobjekt erstellen.
class Konstante:
def __init__(self, value=None):
self.value = value
def __get__(self, instanz, eigentuemer):
return self.value
def __set__(self, instanz, value):
raise ValueError("Du kannst eine Konstante nicht ändern")
1) Wenn wir mit Konstanten auf der Instanzebene arbeiten möchten, dann:
class A:
NULL = Konstante()
NUM = Konstante(0xFF)
class B:
NAME = Konstante('bar')
LISTA = Konstante([0,1,'UNENDLICH'])
>>> obj=A()
>>> print(obj.NUM) #=> 255
>>> obj.NUM =100
Traceback (most recent call last):
File "", line 1, in
ValueError: Du kannst eine Konstante nicht ändern
2) Wenn wir Konstanten nur auf Klassenebene erstellen möchten, könnten wir eine Metaklasse verwenden, die als Container für unsere Konstanten (unsere Deskriptorobjekte) dient; alle absteigenden Klassen erben unsere Konstanten (unsere Deskriptorobjekte) ohne das Risiko, dass sie geändert werden können.
# Metaklasse meiner Klasse Foo
class FooMeta(type): pass
# Klasse Foo
class Foo(metaclass=FooMeta): pass
# Ich erstelle Konstanten in meiner Metaklasse
FooMeta.NUM = Konstante(0xff)
FooMeta.NAME = Konstante('FOO')
>>> Foo.NUM #=> 255
>>> Foo.NAME #=> 'FOO'
>>> Foo.NUM = 0 #=> ValueError: Du kannst eine Konstante nicht ändern
Wenn ich eine Unterklasse von Foo erstelle, wird diese Klasse die Konstante erben, ohne die Möglichkeit, sie zu ändern
class Bar(Foo): pass
>>> Bar.NUM #=> 255
>>> Bar.NUM = 0 #=> ValueError: Du kannst eine Konstante nicht ändern
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.