Comment créer une constante en Python?

y a-t-il un moyen de déclarer une constante en Python? En Java, nous pouvons créer des valeurs constantes de cette manière:

public static final String CONST_NAME = "Name";

Quel est l'équivalent de la déclaration Java constante ci-dessus en Python?

736
demandé sur Steven Vascellaro 0000-00-00 00:00:00

30 réponses

Non, il n'y en a pas. Vous ne pouvez pas déclarer une variable ou une valeur comme constante en Python. Il suffit de ne pas le modifier.

Si vous êtes dans une classe, l'équivalent serait:

class Foo(object):
    CONST_NAME = "Name"

si non, il est juste

CONST_NAME = "Name"

mais vous pourriez vouloir jeter un oeil à l'extrait de code constantes en Python par Alex Martelli.

742
répondu Felix Kling 2013-05-30 21:16:38

il n'y a pas de const mot-clé comme dans d'autres langues, mais il est possible de créer une propriété que a une" fonction getter " pour lire les données, mais pas de" fonction setter " pour réécrire les données. cela protège essentiellement l'identificateur contre toute modification.

Voici une implémentation alternative utilisant la propriété de classe:

noter que le code est loin d'être facile pour un lecteur qui s'interroge sur les constantes. Voir explication ci-dessous

def constant(f):
    def fset(self, value):
        raise TypeError
    def fget(self):
        return f()
    return property(fget, fset)

class _Const(object):
    @constant
    def FOO():
        return 0xBAADFACE
    @constant
    def BAR():
        return 0xDEADBEEF

CONST = _Const()

print CONST.FOO
##3131964110

CONST.FOO = 0
##Traceback (most recent call last):
##    ...
##    CONST.FOO = 0
##TypeError: None

Code Explication:

  1. Définir une fonction constant qui prend une expression, et l'utilise pour construire un "getter" - une fonction qui ne retourne la valeur de l'expression.
  2. la fonction setter soulève une erreur de typographie donc c'est en lecture seule
  3. utilisez la fonction constant que nous venons de créer comme décoration pour définir rapidement les propriétés en lecture seule.

et d'une autre manière plus ancienne:

(le code est assez délicat, plus d'Explications ci-dessous)

class _Const(object):
    @apply
    def FOO():
        def fset(self, value):
            raise TypeError
        def fget(self):
            return 0xBAADFACE
        return property(**locals())

CONST = _Const()

print CONST.FOO
##3131964110

CONST.FOO = 0
##Traceback (most recent call last):
##    ...
##    CONST.FOO = 0
##TypeError: None

notez que le décorateur @apply semble être déprécié.

  1. pour définir L'identifiant FOO, les premiers définissent deux fonctions (fset, fget - les noms sont à mon choix).
  2. puis utilisez la fonction intégrée property pour construire un objet qui peut être" set "ou"get".
  3. notez que les deux premiers paramètres de la fonction property sont appelés fset et fget .
  4. utilisez le fait que nous avons choisi ces mêmes noms pour notre propre getter & setter et créer un mot-dictionnaire en utilisant le * * (double astérisque) appliqué à toutes les définitions locales de ce champ d'application pour passer les paramètres à la property fonction
298
répondu inv 2016-04-06 08:23:17

en Python au lieu du langage enforcing something, les gens utilisent des conventions de nommage E. g __method pour les méthodes privées et _method pour les méthodes protégées.

donc de la même manière vous pouvez simplement déclarer la constante comme tous les capuchons par ex.

MY_CONSTANT = "one"

si vous voulez que cette constante ne change jamais, vous pouvez vous connecter à l'accès aux attributs et faire des trucs, mais une approche plus simple est de déclarer une fonction

def MY_CONSTANT():
    return "one"

seul problème est partout où vous devrez faire MY_CONSTANT(), mais encore une fois MY_CONSTANT = "one" est la bonne façon en python(habituellement).

vous pouvez également utiliser namedtuple pour créer des constantes:

>>> from collections import namedtuple
>>> Constants = namedtuple('Constants', ['pi', 'e'])
>>> constants = Constants(3.14, 2.718)
>>> constants.pi
3.14
>>> constants.pi = 3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
83
répondu Anurag Uniyal 2015-01-02 19:46:01

je suis probablement en train de manquer un tour ici, mais cela semble fonctionner pour moi:

class CONST(object):
    FOO = 1234

    def __setattr__(self, *_):
        pass

CONST = CONST()

#----------

print CONST.FOO    # 1234

CONST.FOO = 4321
CONST.BAR = 5678

print CONST.FOO    # Still 1234!
print CONST.BAR    # Oops AttributeError

la création de l'instance permet à la méthode magique __setattr__ de démarrer et d'intercepter les tentatives de définir la variable FOO . Vous pourriez faire une exception. L'instanciation de l'instance sur le nom de la classe empêche l'accès directement via la classe.

c'est une douleur totale pour une valeur, mais vous pourriez attacher des lots à votre CONST objet. Ayant une classe supérieure, nom de classe semble également un peu grotty, mais je pense qu'il est assez succinct dans l'ensemble.

33
répondu Jon Betts 2014-04-24 16:17:58

comme vous le savez probablement déjà, Python n'a pas de constantes: (

peut-être l'alternative la plus simple est de définir une fonction pour elle. E. g.

def MY_CONSTANT():
    return 42

MY_CONSTANT() a maintenant toutes les fonctionnalités d'une constante (plus quelques ennuyeux accolades).

16
répondu Saeed Baig 2018-03-14 23:00:35

en plus des deux premières réponses (il suffit d'utiliser des variables avec des noms en majuscules, ou d'utiliser des propriétés pour rendre les valeurs en lecture seule), je tiens à mentionner qu'il est possible d'utiliser des métaclasses afin de mettre en œuvre nommé constantes. Je propose une solution très simple en utilisant des métaclasses à GitHub qui peut être utile si vous voulez que les valeurs soient plus informatives sur leur type/ nom:

>>> from named_constants import Constants
>>> class Colors(Constants):
...     black = 0
...     red = 1
...     white = 15
...
>>> c = Colors.black
>>> c == 0
True
>>> c
Colors.black
>>> c.name()
'black'
>>> Colors(0) is c
True

c'est un peu Python plus avancé, mais encore très facile à utiliser et pratique. (Le module a quelques caractéristiques supplémentaires, y compris les constantes étant en lecture seule, voir son README.)

il y a des solutions similaires qui flottent dans divers dépôts, mais à ma connaissance, soit elles manquent d'une des caractéristiques fondamentales que j'attendrais de constantes (comme être constant, OU être de type arbitraire), soit elles ont des caractéristiques ésotériques ajoutées qui les rendent moins applicables. Mais YMMV, je vous serais reconnaissant de me faire part de vos commentaires. :- )

15
répondu hans_meine 2013-10-10 21:25:47

modifier: ajout de code d'échantillon pour Python 3

Note: cette autre réponse semble fournir une mise en œuvre beaucoup plus complète similaire à la suivante (avec plus de fonctionnalités).

tout d'Abord, faire un métaclasse :

class MetaConst(type):
    def __getattr__(cls, key):
        return cls[key]

    def __setattr__(cls, key, value):
        raise TypeError

ceci empêche les propriétés statiques d'être changées. Ensuite, faites une autre classe qui utilise ce metaclass:

class Const(object):
    __metaclass__ = MetaConst

    def __getattr__(self, name):
        return self[name]

    def __setattr__(self, name, value):
        raise TypeError

ou, si vous utilisez Python 3:

class Const(object, metaclass=MetaConst):
    def __getattr__(self, name):
        return self[name]

    def __setattr__(self, name, value):
        raise TypeError

ceci devrait empêcher les props d'instance d'être changés. Pour l'utiliser, hériter:

class MyConst(Const):
    A = 1
    B = 2

maintenant les accessoires, accessibles directement ou via une instance, doivent être constants:

MyConst.A
# 1
my_const = MyConst()
my_const.A
# 1

MyConst.A = 'changed'
# TypeError
my_const.A = 'changed'
# TypeError

Voici un exemple de ci-dessus dans l'action. Voici un autre exemple pour Python 3.

12
répondu doubleswirve 2017-05-23 12:18:28

voici une implémentation d'une classe de" constantes", qui crée des instances avec des attributs en lecture seule (constante). Par exemple: peut utiliser Nums.PI pour obtenir une valeur qui a été initialisée comme 3.14159 , et Nums.PI = 22 soulève une exception.

# ---------- Constants.py ----------
class Constants(object):
    """
    Create objects with read-only (constant) attributes.
    Example:
        Nums = Constants(ONE=1, PI=3.14159, DefaultWidth=100.0)
        print 10 + Nums.PI
        print '----- Following line is deliberate 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)

    # NOTE: This is only called if self lacks the attribute.
    # So it does not interfere with get of 'self._d', etc.
    def __getattr__(self, name):
        return self._d[name]

    # ASSUMES '_..' attribute is OK to set. Need this to initialize 'self._d', etc.
    #If use as keys, they won't be constant.
    def __setattr__(self, name, value):
        if (name[0] == '_'):
            super(Constants, self).__setattr__(name, value)
        else:
            raise ValueError("setattr while locked", self)

if (__name__ == "__main__"):
    # Usage example.
    Nums = Constants(ONE=1, PI=3.14159, DefaultWidth=100.0)
    print 10 + Nums.PI
    print '----- Following line is deliberate ValueError -----'
    Nums.PI = 22

merci à le FrozenDict de @MikeGraham , que j'ai utilisé comme point de départ. Modifié, donc au lieu de Nums['ONE'] la syntaxe d'usage est Nums.ONE .

et merci à la réponse de @Raufio, pour l'idée de passer outre _ _ setattr__.

ou pour une implémentation avec plus de fonctionnalités, voir @Hans_meine named_constants sur GitHub

6
répondu ToolmakerSteve 2017-05-23 11:47:30
Les propriétés

sont une façon de créer des constantes. Vous pouvez le faire en déclarant une propriété getter, mais en ignorant le setter. Par exemple:

class MyFinalProperty(object):

    @property
    def name(self):
        return "John"

vous pouvez jeter un oeil à un article que j'ai écrit pour trouver plus de façons d'utiliser les propriétés de Python.

6
répondu nvd 2017-07-12 23:14:46

je ferais une classe qui surpasse la méthode __setattr__ de la classe d'objet de base et envelopper mes constantes avec cela, notez que j'utilise python 2.7:

class const(object):
    def __init__(self, val):
        super(const, self).__setattr__("value", val)
    def __setattr__(self, name, val):
        raise ValueError("Trying to change a constant value", self)

pour envelopper une corde:

>>> constObj = const("Try to change me")
>>> constObj.value
'Try to change me'
>>> constObj.value = "Changed"
Traceback (most recent call last):
   ...
ValueError: Trying to change a constant value
>>> constObj2 = const(" or not")
>>> mutableObj = constObj.value + constObj2.value
>>> mutableObj #just a string
'Try to change me or not'

c'est assez simple, mais si vous voulez utiliser vos constantes comme vous le feriez un objet non-constant (sans utiliser constObj.valeur), il sera un peu plus intensif. Il est possible que cela puisse causer des problèmes, il est préférable de garder le .value pour montrer et savoir que vous effectuez des opérations avec des constantes (peut-être pas la façon la plus "pythonique").

4
répondu Raufio 2013-06-10 00:09:10

malheureusement le Python n'a pas encore de constantes et c'est dommage. ES6 a déjà ajouté des constantes de soutien à JavaScript ( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/const ) car c'est une chose très utile dans n'importe quel langage de programmation. Comme répondu dans d'autres réponses dans la communauté Python utilisez la variable convention - user uppercase comme constante, mais elle ne protège pas contre les erreurs arbitraires dans le code. Si vous voulez, vous pouvez être trouvé utile un fichier unique solution suivante (voir les docstrings comment l'utiliser).

fichier constants.py

import collections


__all__ = ('const', )


class Constant(object):
    """
    Implementation strict constants in Python 3.

    A constant can be set up, but can not be changed or deleted.
    Value of constant may any immutable type, as well as list or set.
    Besides if value of a constant is list or set, it will be converted in an immutable type as next:
        list -> tuple
        set -> frozenset
    Dict as value of a constant has no support.

    >>> const = Constant()
    >>> del const.temp
    Traceback (most recent call last):
    NameError: name 'temp' is not defined
    >>> const.temp = 1
    >>> const.temp = 88
    Traceback (most recent call last):
        ...
    TypeError: Constanst can not be changed
    >>> del const.temp
    Traceback (most recent call last):
        ...
    TypeError: Constanst can not be deleted
    >>> const.I = ['a', 1, 1.2]
    >>> print(const.I)
    ('a', 1, 1.2)
    >>> const.F = {1.2}
    >>> print(const.F)
    frozenset([1.2])
    >>> const.D = dict()
    Traceback (most recent call last):
        ...
    TypeError: dict can not be used as constant
    >>> del const.UNDEFINED
    Traceback (most recent call last):
        ...
    NameError: name 'UNDEFINED' is not defined
    >>> const()
    {'I': ('a', 1, 1.2), 'temp': 1, 'F': frozenset([1.2])}
    """

    def __setattr__(self, name, value):
        """Declaration a constant with value. If mutable - it will be converted to immutable, if possible.
        If the constant already exists, then made prevent againt change it."""

        if name in self.__dict__:
            raise TypeError('Constanst can not be changed')

        if not isinstance(value, collections.Hashable):
            if isinstance(value, list):
                value = tuple(value)
            elif isinstance(value, set):
                value = frozenset(value)
            elif isinstance(value, dict):
                raise TypeError('dict can not be used as constant')
            else:
                raise ValueError('Muttable or custom type is not supported')
        self.__dict__[name] = value

    def __delattr__(self, name):
        """Deny against deleting a declared constant."""

        if name in self.__dict__:
            raise TypeError('Constanst can not be deleted')
        raise NameError("name '%s' is not defined" % name)

    def __call__(self):
        """Return all constans."""

        return self.__dict__


const = Constant()


if __name__ == '__main__':
    import doctest
    doctest.testmod()

si cela ne suffit pas, voir la fiche complète.

import decimal
import uuid
import datetime
import unittest

from ..constants import Constant


class TestConstant(unittest.TestCase):
    """
    Test for implementation constants in the Python
    """

    def setUp(self):

        self.const = Constant()

    def tearDown(self):

        del self.const

    def test_create_constant_with_different_variants_of_name(self):

        self.const.CONSTANT = 1
        self.assertEqual(self.const.CONSTANT, 1)
        self.const.Constant = 2
        self.assertEqual(self.const.Constant, 2)
        self.const.ConStAnT = 3
        self.assertEqual(self.const.ConStAnT, 3)
        self.const.constant = 4
        self.assertEqual(self.const.constant, 4)
        self.const.co_ns_ta_nt = 5
        self.assertEqual(self.const.co_ns_ta_nt, 5)
        self.const.constant1111 = 6
        self.assertEqual(self.const.constant1111, 6)

    def test_create_and_change_integer_constant(self):

        self.const.INT = 1234
        self.assertEqual(self.const.INT, 1234)
        with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
            self.const.INT = .211

    def test_create_and_change_float_constant(self):

        self.const.FLOAT = .1234
        self.assertEqual(self.const.FLOAT, .1234)
        with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
            self.const.FLOAT = .211

    def test_create_and_change_list_constant_but_saved_as_tuple(self):

        self.const.LIST = [1, .2, None, True, datetime.date.today(), [], {}]
        self.assertEqual(self.const.LIST, (1, .2, None, True, datetime.date.today(), [], {}))

        self.assertTrue(isinstance(self.const.LIST, tuple))

        with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
            self.const.LIST = .211

    def test_create_and_change_none_constant(self):

        self.const.NONE = None
        self.assertEqual(self.const.NONE, None)
        with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
            self.const.NONE = .211

    def test_create_and_change_boolean_constant(self):

        self.const.BOOLEAN = True
        self.assertEqual(self.const.BOOLEAN, True)
        with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
            self.const.BOOLEAN = False

    def test_create_and_change_string_constant(self):

        self.const.STRING = "Text"
        self.assertEqual(self.const.STRING, "Text")

        with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
            self.const.STRING += '...'

        with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
            self.const.STRING = 'TEst1'

    def test_create_dict_constant(self):

        with self.assertRaisesRegexp(TypeError, 'dict can not be used as constant'):
            self.const.DICT = {}

    def test_create_and_change_tuple_constant(self):

        self.const.TUPLE = (1, .2, None, True, datetime.date.today(), [], {})
        self.assertEqual(self.const.TUPLE, (1, .2, None, True, datetime.date.today(), [], {}))

        with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
            self.const.TUPLE = 'TEst1'

    def test_create_and_change_set_constant(self):

        self.const.SET = {1, .2, None, True, datetime.date.today()}
        self.assertEqual(self.const.SET, {1, .2, None, True, datetime.date.today()})

        self.assertTrue(isinstance(self.const.SET, frozenset))

        with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
            self.const.SET = 3212

    def test_create_and_change_frozenset_constant(self):

        self.const.FROZENSET = frozenset({1, .2, None, True, datetime.date.today()})
        self.assertEqual(self.const.FROZENSET, frozenset({1, .2, None, True, datetime.date.today()}))

        with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
            self.const.FROZENSET = True

    def test_create_and_change_date_constant(self):

        self.const.DATE = datetime.date(1111, 11, 11)
        self.assertEqual(self.const.DATE, datetime.date(1111, 11, 11))

        with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
            self.const.DATE = True

    def test_create_and_change_datetime_constant(self):

        self.const.DATETIME = datetime.datetime(2000, 10, 10, 10, 10)
        self.assertEqual(self.const.DATETIME, datetime.datetime(2000, 10, 10, 10, 10))

        with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
            self.const.DATETIME = None

    def test_create_and_change_decimal_constant(self):

        self.const.DECIMAL = decimal.Decimal(13123.12312312321)
        self.assertEqual(self.const.DECIMAL, decimal.Decimal(13123.12312312321))

        with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
            self.const.DECIMAL = None

    def test_create_and_change_timedelta_constant(self):

        self.const.TIMEDELTA = datetime.timedelta(days=45)
        self.assertEqual(self.const.TIMEDELTA, datetime.timedelta(days=45))

        with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
            self.const.TIMEDELTA = 1

    def test_create_and_change_uuid_constant(self):

        value = uuid.uuid4()
        self.const.UUID = value
        self.assertEqual(self.const.UUID, value)

        with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
            self.const.UUID = []

    def test_try_delete_defined_const(self):

        self.const.VERSION = '0.0.1'
        with self.assertRaisesRegexp(TypeError, 'Constanst can not be deleted'):
            del self.const.VERSION

    def test_try_delete_undefined_const(self):

        with self.assertRaisesRegexp(NameError, "name 'UNDEFINED' is not defined"):
            del self.const.UNDEFINED

    def test_get_all_defined_constants(self):

        self.assertDictEqual(self.const(), {})

        self.const.A = 1
        self.assertDictEqual(self.const(), {'A': 1})

        self.const.B = "Text"
        self.assertDictEqual(self.const(), {'A': 1, 'B': "Text"})

avantages: 1. L'accès à toutes les constantes pour l'ensemble du projet 2. Contrôle Strict des valeurs des constantes

manque: 1. Pas de support pour les types personnalisés et le type "dict "

Notes:

  1. Testé avec Python3.4 et Python3.5 (je vais utiliser le "tox")

  2. environnement de Test:

.

$ uname -a
Linux wlysenko-Aspire 3.13.0-37-generic #64-Ubuntu SMP Mon Sep 22 21:28:38 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
4
répondu Seti Volkylany 2017-01-06 01:09:13

la façon pythonique de déclarer "constantes" est fondamentalement une variable de niveau de module:

RED = 1
GREEN = 2
BLUE = 3

et ensuite écrire vos cours ou fonctions. Puisque les constantes sont presque toujours des entiers, et qu'elles sont également immuables en Python, vous avez très peu de chance de les modifier.

sauf, bien sûr, si vous définissez explicitement RED = 2 .

3
répondu Xavier Ho 2010-04-21 13:28:28

un tuple se qualifie techniquement comme une constante, car un tuple soulèvera une erreur si vous essayez de changer une de ses valeurs. Si vous voulez déclarer un tuple avec une valeur, puis placez une virgule après sa seule valeur, comme ceci:

my_tuple = (0 """Or any other value""",)

pour vérifier la valeur de cette variable, utilisez quelque chose de similaire à ceci:

if my_tuple[0] == 0:
    #Code goes here

Si vous tentez de modifier cette valeur, une erreur sera générée.

3
répondu tobahhh 2016-05-09 21:51:12

Vous pouvez utiliser une namedtuple comme une solution de contournement pour créer efficacement une constante qui fonctionne de la même manière statique dernière variable en Java (Java "constant"). Que des solutions de contournement aller, c'est une sorte d'élégant. (Une approche plus élégante serait d'améliorer simplement le langage Python - - - quelle sorte de langage vous permet de redéfinir math.pi ? -- mais je m'égare.)

(en écrivant ceci, je me rends compte qu'une autre réponse à cette question a été mentionnée, mais je vais continuer ici parce que je vais montrer une syntaxe qui ressemble plus étroitement à ce que vous attendez en Java, car il n'y a pas besoin de créer un nommé "type comme namedtuple vous force à le faire.)

en suivant votre exemple, vous vous souviendrez Qu'en Java nous devons définir la constante dans une classe quelconque ; parce que vous n'avez pas mentionné un nom de classe, appelons-le Foo . Voici la classe Java:

public class Foo {
  public static final String CONST_NAME = "Name";
}

voici le équivalent en Python.

from collections import namedtuple
Foo = namedtuple('_Foo', 'CONST_NAME')('Name')

le point clé que je veux ajouter ici est que vous n'avez pas besoin d'un type Foo séparé (un" un tuple anonyme nommé "serait bien, même si cela ressemble à un oxymore), donc nous appelons notre tuple _Foo de sorte que nous espérons qu'il ne s'échappera pas à l'importation de modules.

le deuxième point ici est que nous immédiatement créer une instance du nametuple, l'appelant Foo ; il n'y a pas besoin de faire cela dans une étape distincte (sauf si vous voulez). Maintenant, vous pouvez faire ce que vous pouvez faire en Java:

>>> Foo.CONST_NAME
'Name'

mais vous ne pouvez pas lui assigner:

>>> Foo.CONST_NAME = 'bar'
…
AttributeError: can't set attribute

reconnaissance: j'ai pensé que j'ai inventé l'approche namedtuple, mais alors je vois que quelqu'un d'autre a donné une réponse similaire (bien que moins compacte). Puis j'ai aussi remarqué Qu'est-ce que "appelé tuples" en Python? , qui souligne que sys.version_info est maintenant un exemple, donc peut-être que la bibliothèque standard de Python a déjà eu cette idée bien plus tôt.

notez que malheureusement (ceci étant encore Python), vous pouvez effacer la totalité de l'affectation Foo tout à fait:

>>> Foo = 'bar'

(facepalm)

mais au moins nous empêchons la valeur Foo.CONST_NAME d'être changée, et c'est mieux que rien. Bonne chance.

3
répondu Garret Wilson 2017-05-23 12:34:47

les dictionnaires Python sont mutables, donc ils ne semblent pas être une bonne façon de déclarer les constantes:

>>> constants = {"foo":1, "bar":2}
>>> print constants
{'foo': 1, 'bar': 2}
>>> constants["bar"] = 3
>>> print constants
{'foo': 1, 'bar': 3}
2
répondu n8boyd 2011-06-30 07:36:28

En python, une constante est simplement une variable avec un nom dans toutes les capitales, avec des mots séparés par le caractère de soulignement

E. g

DAYS_IN_WEEK = 7

la valeur est mutable, comme dans vous pouvez la changer. Mais étant donné les règles pour le nom vous dire est une constante, pourquoi le feriez-vous? Je veux dire, c'est ton programme après tout!

C'est l'approche adoptée dans tout python. Il n'y a pas de private mot-clé pour la même raison. Préfixe le nom avec un underscore et vous savez qu'il est destiné à être privé. Le Code peut briser la règle....tout comme un programmeur pourrait supprimer le mot-clé privé de toute façon.

Python aurait pu ajouter un mot-clé const ... mais un programmeur pourrait supprimer mot clé, puis changement de la constante si ils veulent, mais pourquoi faire? Si tu veux enfreindre la règle, tu peux la changer de toute façon. Mais pourquoi s'embêter à briser la règle si le nom fait l'intention est-elle claire?

peut-être y a-t-il un test unitaire où il est logique d'appliquer un changement de valeur? Pour voir ce qui se passe pendant une semaine de 8 jours même si dans le monde réel le nombre de jours dans la semaine ne peut pas être changé. Si la langue vous a empêché de faire une exception s'il n'y a qu'un seul cas, vous devez enfreindre la règle...il faudrait alors arrêter de la déclarer comme constante, même si c'est encore une constante dans l'application, et il n'y a qu'un seul test cas qui voit ce qui se passe si elle est modifiée.

Le tout en majuscules nom l'indique, il est destiné à être une constante. C'est ce qui est important. Pas un langage forçant des contraintes sur le code vous avez le pouvoir de changer de toute façon.

C'est la philosophie de python.

2
répondu innov8 2018-04-30 12:14:53

simplement vous pouvez juste:

STRING_CONSTANT = "hi"
NUMBER_CONSTANT = 89

l'espoir qui rend tout beaucoup plus simple

2
répondu 2018-05-06 09:15:39

dans mon cas, j'avais besoin d'un bytearrays immuable pour une implémentation d'une bibliothèque de crypto contenant de nombreux nombres littéraux que je voulais assurer étaient constants.

Cette réponse fonctionne, mais la tentative de réaffectation de bytearray éléments ne génère pas d'erreur.

def const(func):
    '''implement const decorator'''
    def fset(self, val):
        '''attempting to set a const raises `ConstError`'''
        class ConstError(TypeError):
            '''special exception for const reassignment'''
            pass

        raise ConstError

    def fget(self):
        '''get a const'''
        return func()

    return property(fget, fset)


class Consts(object):
    '''contain all constants'''

    @const
    def C1():
        '''reassignment to C1 fails silently'''
        return bytearray.fromhex('deadbeef')

    @const
    def pi():
        '''is immutable'''
        return 3.141592653589793

les constantes sont immuables, mais l'assignation de bytearray constante échoue silencieusement:

>>> c = Consts()
>>> c.pi = 6.283185307179586  # (https://en.wikipedia.org/wiki/Tau_(2%CF%80))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  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')

un plus puissant, simple, et peut-être même une approche plus "pythonique" implique l'utilisation d'objets memoryview (objets buffer dans <= 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):
    '''represent a constant bytearray'''
    def __init__(self, init):
        '''
        create a hidden bytearray and expose a memoryview of that bytearray for
        read-only use
        '''
        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)

ConstArray de l'élément de mission TypeError :

>>> C1 = ConstArray('deadbeef')
>>> C1[0] = 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'ConstArray' object does not support item assignment
>>> C1[0]
222
1
répondu jxqz 2015-02-25 16:37:03

j'écris une lib d'util pour python const: kkconst-pypi support str, int, float ,datetime

l'instance du champ const conservera son comportement de type de base.

par exemple:

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"mathematical constant")  # Euler's number"
    GOLDEN_RATIO = ConstFloatField(0.6180339887, verbose_name=u"Golden Ratio")

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)  # Golden Ratio

plus de détails: pypi ou github

"
1
répondu kaka_ace 2015-12-23 10:49:59

vous pouvez envelopper une constante dans un tableau numpy, la marquer en écriture seulement, et toujours l'appeler par index zéro.

import numpy as np

# declare a constant
CONSTANT = 'hello'

# put constant in numpy and make read only
CONSTANT = np.array([CONSTANT])
CONSTANT.flags.writeable = False
# alternatively: CONSTANT.setflags(write=0)

# call our constant using 0 index    
print 'CONSTANT %s' % CONSTANT[0]

# attempt to modify our constant with try/except
new_value = 'goodbye'
try:
    CONSTANT[0] = new_value
except:
    print "cannot change CONSTANT to '%s' it's value '%s' is immutable" % (
        new_value, CONSTANT[0])

# attempt to modify our constant producing ValueError
CONSTANT[0] = new_value



>>>
CONSTANT hello
cannot change CONSTANT to 'goodbye' it's value 'hello' is immutable
Traceback (most recent call last):
  File "shuffle_test.py", line 15, in <module>
    CONSTANT[0] = new_value
ValueError: assignment destination is read-only

bien sûr, cela ne protège que le contenu du numpy, pas la variable "constante" elle-même; vous pouvez encore faire:

CONSTANT = 'foo'

et CONSTANT changeraient, mais cela lancerait rapidement une erreur typographique la première fois CONSTANT[0] est plus tard appelé dans le script.

bien que... Je suppose que si vous à un moment donné changé en

CONSTANT = [1,2,3]

maintenant tu n'aurais plus le TypeError. hmmmm....

https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.setflags.html

1
répondu litepresence 2017-04-01 04:25:37

nous pouvons créer un objet descripteur:

class Constant:
  def __init__(self,value=None):
    self.value = value
  def __get__(self,instance,owner):
    return self.value
  def __set__(self,instance,value):
    raise ValueError("You can't change a constant")

class A:
  NULL = Constant()
  NUM = Constant(0xFF)

class B:
  NAME = Constant('bar')
  LISTA = Constant([0,1,'INFINITY'])

>>> obj=A()
>>> print(obj.NUM)  #=> 255
>>> obj.NUM =100

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: You can't change a constant
1
répondu MVP 2017-05-12 15:57:09

Voici une astuce si vous voulez des constantes et ne vous souciez pas de leurs valeurs:

il suffit de définir les classes vides.

E. g:

class RED: 
    pass
class BLUE: 
    pass
1
répondu Lym Zoy 2017-08-11 07:03:36

vous pouvez utiliser StringVar ou IntVar, etc, votre constante est const_val

val = 'Stackoverflow'
const_val = StringVar(val)
const.trace('w', reverse)

def reverse(*args):
    const_val.set(val)
1
répondu Nqobizwe 2017-09-30 08:53:48

en Python, les constantes n'existent pas. Mais vous pouvez indiquer qu'une variable est une constante et ne doit pas être changée en ajoutant '_CONSTANT ' au début du nom de la variable, en nommant la variable en majuscules de bloc, et en ajoutant un commentaire en utilisant le hashtag (' # ') par exemple:

    normal_variable = 0
    CONSTANT_variable = 1    # This is a constant - do not change its value!   
1
répondu Aryan Beezadhur 2017-12-14 20:03:45

en prolongeant la réponse de Raufio, ajouter un repr pour retourner la valeur.

class const(object):
    def __init__(self, val):
        super(const, self).__setattr__("value", val)
    def __setattr__(self, name, val):
        raise ValueError("Trying to change a constant value", self)
    def __repr__(self):
        return ('{0}'.format(self.value))

dt = const(float(0.01))
print dt

alors l'objet se comporte un peu plus comme vous pourriez vous y attendre, vous pouvez y accéder directement plutôt que".valeur

0
répondu Jonathan Kimball Galloway 2013-09-26 15:10:23

bien.. bien que cela soit dépassé, permettez-moi d'ajouter mes 2 cents ici: -)

class ConstDict(dict):
    def __init__(self, *args, **kwargs):
        super(ConstDict, self).__init__(*args, **kwargs)

    def __setitem__(self, key, value):
        if key in self:
            raise ValueError("Value %s already exists" % (key))
        super(ConstDict, self).__setitem__(key, value)

au lieu de ValueError de casser, vous pouvez empêcher toute mise à jour qui se produit là. Un avantage de ceci est que vous pouvez ajouter des constantes dynamiquement dans le programme mais vous ne pouvez pas changer une fois qu'une constante est définie. Vous pouvez aussi ajouter n'importe quelle règle ou n'importe quoi avant de définir une constante(quelque chose comme la clé doit être une chaîne ou une chaîne de minuscules ou de minuscules et ainsi de suite avant de définir la clé)

cependant, je ne vois aucune importance de définir des constantes en Python. Aucune optimisation ne peut se produire comme en C et c'est donc quelque chose qui n'est pas nécessaire, je suppose.

0
répondu thiruvenkadam 2015-01-20 13:03:28

vous pouvez émuler des variables constantes à l'aide de la classe suivante. Un exemple d'usage:

# Const
const = Const().add(two=2, three=3)

print 'const.two: ', const.two
print 'const.three: ', const.three

const.add(four=4)

print 'const.four: ', const.four

#const.four = 5 # a error here: four is a constant

const.add(six=6)

print 'const.six: ', const.six

const2 = Const().add(five=5) # creating a new namespace with Const()
print 'const2.five: ', const2.five
#print 'const2.four: ', const2.four # a error here: four does not exist in const2 namespace

const2.add(five=26)

appelez le constructeur quand vous voulez démarrer un nouvel espace de noms constant. Il est à noter que la classe est sous protection de modifier des constantes de type de séquence inattendues lorsque la classe const de Martelli ne l'est pas.

la source est ci-dessous.

from copy import copy

class Const(object):
"A class to create objects with constant fields."

def __init__(self):
    object.__setattr__(self, '_names', [])


def add(self, **nameVals):
    for name, val in nameVals.iteritems():          
        if hasattr(self, name):
            raise ConstError('A field with a name \'%s\' is already exist in Const class.' % name)

        setattr(self, name, copy(val)) # set up getter

        self._names.append(name)

    return self


def __setattr__(self, name, val):
    if name in self._names:
        raise ConstError('You cannot change a value of a stored constant.')

    object.__setattr__(self, name, val)
0
répondu sergzach 2017-03-27 16:36:11

il n'y a pas de moyen parfait pour faire ça. Si je comprends bien, la plupart des programmeurs vont simplement capitaliser L'identifiant, de sorte que PI = 3.142 peut être facilement compris comme une constante.

d'un autre côté, si vous voulez quelque chose qui agit comme une constante, Je ne suis pas sûr que vous le trouverez. Avec tout ce que vous faites, il y aura toujours un moyen d'éditer la "constante", donc ce ne sera pas vraiment une constante. Voici un très simple, sale exemple:

def define(name, value):
  if (name + str(id(name))) not in globals():
    globals()[name + str(id(name))] = value

def constant(name):
  return globals()[name + str(id(name))]

define("PI",3.142)

print(constant("PI"))

on dirait qu'il va faire une constante de style PHP.

en réalité, tout ce qu'il faut pour que quelqu'un change la valeur est ceci:

globals()["PI"+str(id("PI"))] = 3.1415

c'est la même chose pour toutes les autres solutions que vous trouverez ici - même les plus intelligentes qui font une classe et redéfinissent la méthode des attributs set - il y aura toujours un moyen de les contourner. C'est comme ça Qu'est Python.

ma recommandation est d'éviter tous les tracas et juste capitaliser vos identifiants. Il ne serait pas vraiment une bonne constante, mais là encore, rien n'aurait.

0
répondu John 2018-07-23 14:02:11

(ce paragraphe était censé être un commentaire sur les réponses ici et , qui mentionnaient namedtuple , mais il prend trop de temps pour être intégré dans un commentaire, Donc, voilà.)

l'approche namedtuple mentionnée ci-dessus est certainement innovatrice. Par souci d'exhaustivité, cependant, à la fin de la section intitulée sa documentation officielle , elle se lit comme suit:

les constantes énumérées peuvent être mises en œuvre avec les tuples nommés, mais il est plus simple et plus efficace d'utiliser une déclaration de classe simple:

class Status:
    open, pending, closed = range(3)

en d'autres termes, la documentation officielle préfère utiliser une méthode pratique, plutôt que de mettre en œuvre le comportement en lecture seule. Je suppose qu'il devient encore un autre exemple de Zen de Python :

Simple est mieux que complexe.

la praticité bat la pureté.

0
répondu RayLuo 2018-09-06 00:05:43

il y a une façon plus propre de le faire avec namedtuple:

from collections import namedtuple


def make_consts(name, **kwargs):
    return namedtuple(name, kwargs.keys())(**kwargs)

Exemple D'Utilisation

CONSTS = make_consts("baz1",
                     foo=1,
                     bar=2)

avec cette approche exacte vous pouvez namespace vos constantes.

0
répondu Juan Ignacio Sánchez 2018-09-13 05:01:01