1275 Stimmen

Wie erstelle ich eine Konstante in Python?

Wie deklariere ich eine Konstante in Python?

In Java machen wir:

public static final String CONST_NAME = "Name";

2voto

Jaunty Sankey Punkte 31

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

1voto

litepresence Punkte 2795

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

1voto

kaka_ace Punkte 337

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

1voto

simon Punkte 729

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

1voto

jxqz Punkte 109

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.com

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.

Powered by:

X