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";
Sie können es mit collections.namedtuple
und itertools
machen:
import collections
import itertools
def Konstanten(Name, *Args, **Kwargs):
t = collections.namedtuple(Name, itertools.chain(Args, Kwargs.keys()))
return t(*itertools.chain(Args, Kwargs.values()))
>>> meineKonstanten = Konstanten('MeineKonstanten', 'Eins', 'Zwei', Drei = 'Vier')
>>> print meineKonstanten.Eins
Eins
>>> print meineKonstanten.Zwei
Zwei
>>> print meineKonstanten.Drei
Vier
>>> meineKonstanten.Eins = 'Zwei'
Traceback (most recent call last):
File "", line 1, in
AttributeError: kann Attribut nicht setzen
Sie können eine Konstante in ein numpy-Array einpacken, es als schreibgeschützt kennzeichnen und es immer mit Index null aufrufen.
import numpy as np
# eine Konstante deklarieren
CONSTANT = 'hallo'
# Konstante in ein numpy-Array einfügen und schreibgeschützt machen
CONSTANT = np.array([CONSTANT])
CONSTANT.flags.writeable = False
# alternativ: CONSTANT.setflags(write=0)
# Aufruf unserer Konstanten unter Verwendung des Index 0
print 'CONSTANT %s' % CONSTANT[0]
# Versuch unsere Konstante mit try/except zu ändern
neuer_wert = 'auf wiedersehen'
try:
CONSTANT[0] = neuer_wert
except:
print "Kann CONSTANT nicht auf '%s' ändern. Der Wert 'hello' ist unveränderlich" % (
neuer_wert, CONSTANT[0])
# Versuch unsere Konstante zu ändern, was ValueError ergibt
CONSTANT[0] = neuer_wert
>>>
CONSTANT hallo
Kann CONSTANT nicht auf 'auf wiedersehen' ändern. Der Wert 'hallo' ist unveränderlich
Traceback (most recent call last):
File "shuffle_test.py", line 15, in
CONSTANT[0] = neuer_wert
ValueError: assignment destination is read-only
Natürlich schützt dies nur den Inhalt des numpy, nicht die Variable "CONSTANT" selbst; Sie können immer noch Folgendes tun:
CONSTANT = 'foo'
und CONSTANT
würde sich ändern, jedoch würde dies schnell einen TypeError auslösen, wenn später im Skript CONSTANT[0]
aufgerufen wird.
obwohl... Ich nehme an, wenn Sie es irgendwann auf
CONSTANT = [1,2,3]
ändern würden, würden Sie den TypeError nicht mehr bekommen. Hmmmm....
https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.setflags.html
Ich schreibe eine Hilfsbibliothek für Python const: kkconst - pypi Unterstützt str, int, float, datetime
Die Konstantenfeld-Instanz behält ihr Basistypverhalten bei.
Zum Beispiel:
from __future__ import print_function
from kkconst import (
BaseConst,
ConstFloatField,
)
class MathConst(BaseConst):
PI = ConstFloatField(3.1415926, verbose_name=u"Pi")
E = ConstFloatField(2.7182818284, verbose_name=u"Mathematische Konstante") # Eulersche Zahl
GOLDEN_RATIO = ConstFloatField(0.6180339887, verbose_name=u"Goldener Schnitt")
magic_num = MathConst.GOLDEN_RATIO
assert isinstance(magic_num, ConstFloatField)
assert isinstance(magic_num, float)
print(magic_num) # 0.6180339887
print(magic_num.verbose_name) # Goldener Schnitt
Weitere Details zur Verwendung finden Sie unter der pypi-URL: pypi oder github
Ich weiß, dass dies eine alte Frage ist, aber da immer noch neue Lösungen hinzugefügt werden, möchte ich die Liste der möglichen Lösungen noch vollständiger machen. Sie könnten Konstanten innerhalb von Instanzen implementieren, indem Sie von einer Klasse wie der folgenden erben:
class ConstantError(Exception):
pass # vielleicht eine nette Fehlermeldung geben
class AllowConstants:
_constants = None
_class_constants = None
def __init__(self):
self._constants = {}
if self._class_constants is not None:
self._constants.update(self._class_constants)
def constant(self, name, value):
assert isinstance(name, str)
assert self._constants is not None, "AllowConstants wurde nicht initialisiert"
if name in self._constants or name in self.__dict__:
raise ConstantError(name)
self._constants[name] = value
def __getattr__(self, attr):
if attr in self._constants:
return self._constants[attr]
raise AttributeError(attr)
def __setattr__(self, attr, val):
if self._constants is None:
# nicht fertige Initialisierung
self.__dict__[attr] = val
else:
if attr in self._constants:
raise ConstantError(attr)
else:
self.__dict__[attr] = val
def __dir__(self):
return super().__dir__() + list(self._constants.keys())
Beim Unterklassen dieser Klasse werden die von Ihnen erstellten Konstanten geschützt:
class Beispiel(AllowConstants):
def __init__(self, a, b):
super().__init__()
self.constant("b", b)
self.a = a
def try_a(self, value):
self.a = value
def try_b(self, value):
self.b = value
def __str__(self):
return str({"a": self.a, "b": self.b})
def __repr__(self):
return self.__str__()
beispiel = Beispiel(1, 2)
print(beispiel) # {'a': 1, 'b': 2}
beispiel.try_a(5)
print(beispiel) # {'a': 5, 'b': 2}
beispiel.try_b(6) # ConstantError: b
beispiel.a = 7
print(beispiel) # {'a': 7, 'b': 2}
beispiel.b = 8 # ConstantError: b
print(hasattr(beispiel, "b")) # True
# Um zu zeigen, dass Konstanten wirklich sofort konstant werden:
class AnderesBeispiel(AllowConstants):
def __init__(self):
super().__init__()
self.constant("a", 2)
print(self.a)
self.a=3
AnderesBeispiel() # 2 ConstantError: a
# schließlich für Klassenkonstanten:
class NochEinBeispiel(Beispiel):
_class_constants = {
'BLA': 3
}
def __init__(self, a, b):
super().__init__(a,b)
def try_BLA(self, value):
self.BLA = value
ex3 = NochEinBeispiel(10, 20)
ex3.BLA # 3
ex3.try_BLA(10) # ConstantError: BLA
ex3.BLA = 4 # ConstantError: BLA
Konstanten sind lokal (jede Instanz von Klassen, die von AllowConstants erben, hat ihre eigenen Konstanten), verhalten sich wie normale Attribute, solange sie nicht neu zugewiesen werden, und das Schreiben von Klassen, die von dieser Klasse erben, ermöglicht einen mehr oder weniger den gleichen Stil wie bei Sprachen, die Konstanten unterstützen.
Wenn Sie außerdem verhindern möchten, dass jemand die Werte durch direkten Zugriff auf instance._constants ändert, können Sie einen der vielen Container verwenden, die in anderen Antworten vorgeschlagen wurden, die dies nicht zulassen. Schließlich könnten Sie, wenn Sie wirklich das Gefühl haben, dies zu tun, verhindern, dass Personen alle instance._constants auf ein neues Wörterbuch setzen, indem Sie einige weitere Attributzugriffe von AllowConstants verwenden. (Natürlich ist nichts davon sehr pythonisch, aber das ist nicht der Punkt).
Bearbeitung (da es Spaß macht, Python unpythonisch zu machen): Um die Vererbung etwas zu erleichtern, könnte man AllowConstants wie folgt ändern:
class AllowConstants:
_constants = None
_class_constants = None
def __init__(self):
self._constants = {}
self._update_class_constants()
def __init_subclass__(cls):
"""
Ohne dies ist es erforderlich, _class_constants in jeder Unterklasse jeder Klasse, die Klassenkonstanten hat, festzulegen
"""
if cls._class_constants ist not None:
# Probleme verhindern, wenn _class_constants nicht überschrieben wird
mögliche_fälle = cls.__mro__[1:-1] # 0 wird cls haben und -1 wird Objekt haben
for fall in mögliche_fälle:
if cls._class_constants ist fall._class_constants:
cls._class_constants = None
break
def _update_class_constants(self):
"""
Hilft bei der Vererbung von Klassenkonstanten
"""
for überklasse in self.__class__.__mro__:
if hasattr(überklasse, "_class_constants"):
sccc = überklasse._class_constants
if sccc ist not None:
for schlüssel in sccc:
if schlüssel in self._constants:
raise ConstantError(schlüssel)
self._constants.update(sccc)
def constant(self, name, value):
assert isinstance(name, str)
assert self._constants ist not None, "AllowConstants wurde nicht initialisiert"
if name in self._constants or name in self.__dict__:
raise ConstantError(name)
self._constants[name] = value
def __getattr__(self, attr):
if attr in self._constants:
return self._constants[attr]
raise AttributeError(attr)
def __setattr__(self, attr, val):
if self._constants ist None:
# Nicht fertige Initialisierung
self.__dict__[attr] = val
else:
if attr in self._constants:
raise ConstantError(attr)
else:
self.__dict__[attr] = val
def __dir__(self):
return super().__dir__() + list(self._constants.keys())
Auf diese Weise können Sie einfach Folgendes tun:
class Beispiel(AllowConstants):
_class_constants = {
"BLA": 2
}
def __init__(self, a, b):
super().__init__()
self.constant("b", b)
self.a = a
def try_a(self, value):
self.a = value
def try_b(self, value):
self.b = value
def __str__(self):
return str({"a": self.a, "b": self.b})
def __repr__(self):
return self.__str__()
class KindBeispiel1(Beispiel):
_class_constants = {
"BLI": 88
}
class KindBeispiel2(Beispiel):
_class_constants = {
"BLA": 44
}
beispiel = KindBeispiel1(2,3)
print(beispiel.BLA) # 2
beispiel.BLA = 8 # ConstantError BLA
print(beispiel.BLI) # 88
beispiel.BLI = 8 # ConstantError BLI
beispiel = KindBeispiel2(2,3) # ConstantError BLA
In meinem Fall benötigte ich unveränderliche Bytearrays für die Implementierung einer Kryptobibliothek, die viele literal Zahlen enthielt, von denen ich sicherstellen wollte, dass sie konstant waren.
Diese Antwort funktioniert, aber der Versuch der Neuzuweisung von ByteArray-Elementen löst keinen Fehler aus.
def const(func):
'''implementiere const Decorator'''
def fset(self, val):
'''Versuch, ein const auszulösen, wirft `ConstError`'''
class ConstError(TypeError):
'''besondere Ausnahme für const-Zuweisung'''
pass
raise ConstError
def fget(self):
'''Hol dir ein const'''
return func()
return property(fget, fset)
class Consts(object):
'''enthält alle Konstanten'''
@const
def C1():
'''Neuzuweisung zu C1 scheitert geräuschlos'''
return bytearray.fromhex('deadbeef')
@const
def pi():
'''ist unveränderlich'''
return 3.141592653589793
Konstanten sind unveränderlich, aber die Zuweisung von konstanten Bytearrays scheitert geräuschlos:
>>> c = Consts()
>>> c.pi = 6.283185307179586 # (https://en.wikipedia.org/wiki/Tau_(2%CF%80))
Traceback (most recent call last):
File "", line 1, in
File "consts.py", line 9, in fset
raise ConstError
__main__.ConstError
>>> c.C1[0] = 0
>>> c.C1[0]
222
>>> c.C1
bytearray(b'\xde\xad\xbe\xef')
Ein leistungsstärkerer, einfacherer und vielleicht sogar "pythonischer" Ansatz besteht in der Verwendung von memoryview-Objekten (Pufferobjekten in <= Python-2.6).
import sys
PY_VER = sys.version.split()[0].split('.')
if int(PY_VER[0]) == 2:
if int(PY_VER[1]) < 6:
raise NotImplementedError
elif int(PY_VER[1]) == 6:
memoryview = buffer
class ConstArray(object):
'''stelle ein konstantes ByteArray dar'''
def __init__(self, init):
'''
Erstelle ein verstecktes ByteArray und expose ein memoryview dieses ByteArrays für
schreibgeschützte Verwendung
'''
if int(PY_VER[1]) == 6:
self.__array = bytearray(init.decode('hex'))
else:
self.__array = bytearray.fromhex(init)
self.array = memoryview(self.__array)
def __str__(self):
return str(self.__array)
def __getitem__(self, *args, **kwargs):
return self.array.__getitem__(*args, **kwargs)
Item-Zuweisung an ConstArray ist ein TypeError
:
>>> C1 = ConstArray('deadbeef')
>>> C1[0] = 0
Traceback (most recent call last):
File "", line 1, in
TypeError: 'ConstArray' object does not support item assignment
>>> C1[0]
222
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.