¿Cómo puedo crear una constante en Python?


¿Hay alguna forma de declarar una constante en Python? En Java podemos crear valores constantes de esta manera:

public static final String CONST_NAME = "Name";

¿Cuál es el equivalente de la anterior declaración de constantes Java en Python?

Author: Steven Vascellaro, 0000-00-00

30 answers

No, no lo hay. No puede declarar una variable o valor como constante en Python. No lo cambies.

Si estás en una clase, el equivalente sería:

class Foo(object):
    CONST_NAME = "Name"

Si no, es solo

CONST_NAME = "Name"

Pero es posible que desee echar un vistazo al fragmento de código Constantes en Python por Alex Martelli.

 742
Author: Felix Kling,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-30 21:16:38

No hay una palabra clave const como en otros idiomas, sin embargo es posible crear una Propiedad que tiene una "función getter" para leer los datos, pero no hay una "función setter" para volver a escribir los datos. Esto esencialmente protege el identificador de ser cambiado.

Aquí hay una implementación alternativa usando la propiedad class:

Tenga en cuenta que el código está lejos de ser fácil para un lector que se pregunta acerca de las constantes. Ver explicación abajo

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

Explicación Del Código:

  1. Define una función constant que toma una expresión, y la usa para construir un "getter" - una función que solo devuelve el valor de la expresión.
  2. La función setter genera un TypeError por lo que es de solo lectura
  3. Utilice la función constant que acabamos de crear como decoración para definir rápidamente las propiedades de solo lectura.

Y de alguna otra manera más anticuada: {[17]]}

(Las el código es bastante complicado, más explicaciones a continuación)

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

Tenga en cuenta que el decorador @apply parece estar obsoleto.

  1. Para definir el identificador FOO, firs define dos funciones (fset, fget - los nombres están a mi elección).
  2. Luego use la función incorporada property para construir un objeto que puede ser "set" o "get".
  3. Tenga en cuenta que los dos primeros parámetros de la función property se denominan fset y fget.
  4. Utilice el hecho de que elegimos estos muy nombres para nuestro propio getter & setter y crear un diccionario de palabras clave utilizando el * * (asterisco doble) aplicado a todas las definiciones locales de ese ámbito para pasar parámetros a la función property
 298
Author: inv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-06 08:23:17

En Python en lugar de imponer algo por el lenguaje, la gente usa convenciones de nomenclatura, por ejemplo __method para métodos privados y usando _method para métodos protegidos.

Así que de la misma manera, simplemente puede declarar la constante como todas las mayúsculas, por ejemplo,

MY_CONSTANT = "one"

Si desea que esta constante nunca cambie, puede engancharse al acceso de atributos y hacer trucos, pero un enfoque más simple es declarar una función

def MY_CONSTANT():
    return "one"

El único problema es que en todas partes tendrás que hacer MY_CONSTANT(), pero de nuevo MY_CONSTANT = "one" es la forma correcta en python (generalmente).

También puedes usar namedtuple para crear 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
Author: Anurag Uniyal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-02 19:46:01

Probablemente me estoy perdiendo un truco aquí, pero esto parece funcionar para mí:

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 creación de la instancia permite que el método magic __setattr__ inicie e intercepte los intentos de establecer la variable FOO. Podrías hacer una excepción si quisieras. Crear instancias de la instancia sobre el nombre de la clase impide el acceso directamente a través de la clase.

Es un dolor total para un valor, pero podría adjuntar lotes a su objeto CONST. Tener una clase alta, nombre de clase también parece un poco grotesco, pero Creo que es bastante sucinto en general.

 33
Author: Jon Betts,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-24 16:17:58

Como probablemente ya sabes, Python no tiene constantes : (

Quizás la alternativa más fácil es definir una función para ella. E. g.

def MY_CONSTANT():
    return 42

MY_CONSTANT() ahora tiene toda la funcionalidad de una constante (además de algunos frenos molestos).

 16
Author: Saeed Baig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-14 23:00:35

Además de las dos respuestas principales (solo use variables con nombres en MAYÚSCULAS, o use propiedades para hacer que los valores sean de solo lectura), quiero mencionar que es posible usar metaclases para implementar constantes llamadas. Proporciono una solución muy simple usando metaclases en GitHub que puede ser útil si desea que los valores sean más informativos sobre su tipo / nombre:

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

Esto es un poco más avanzado Python, pero sigue siendo muy fácil de usar y práctico. (El módulo tiene algunas características más, incluyendo constantes que son de solo lectura, vea su LÉAME.)

Hay soluciones similares flotando en varios repositorios, pero a lo mejor de mi conocimiento, o bien carecen de una de las características fundamentales que esperaría de las constantes (como ser constante o ser de tipo arbitrario), o tienen características esotéricas agregadas que las hacen menos aplicables en general. Pero YMMV, estaría agradecido por comentarios. :-)

 15
Author: hans_meine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-10 21:25:47

Editar: Se ha añadido código de ejemplo para Python 3

Nota: esta otra respuesta parece que proporciona una implementación mucho más completa similar a la siguiente (con más características).

Primero, haz una metaclase :

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

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

Esto evita que se cambien las propiedades estáticas. Luego haga otra clase que use esa metaclase:

class Const(object):
    __metaclass__ = MetaConst

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

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

O, si estás usando Python 3:

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

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

Esto debería evitar que se cambien las props de instancia. Para usarlo, heredar:

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

Ahora los props, a los que se accede directamente o a través de una instancia, deben ser constantes:

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

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

Aquí está un ejemplo de lo anterior en acción. Aquí está otro ejemplo para Python 3.

 12
Author: doubleswirve,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:28

Aquí hay una implementación de una clase "Constantes", que crea instancias con atributos de solo lectura (constantes). Por ejemplo, puede usar Nums.PI para obtener un valor que se ha inicializado como 3.14159, y Nums.PI = 22 genera una excepción.

# ---------- 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

Gracias a FrozenDict de@MikeGraham, que utilicé como punto de partida. Cambiado, así que en lugar de Nums['ONE'] la sintaxis de uso es Nums.ONE.

Y gracias a la respuesta de @Raufio, por la idea de anular __ setattr __.

O para una implementación con más funcionalidad, ver @Hans_meine named_constants at GitHub

 6
Author: ToolmakerSteve,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:30

Las propiedades son una forma de crear constantes. Puede hacerlo declarando una propiedad getter, pero ignorando al setter. Por ejemplo:

class MyFinalProperty(object):

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

Puedes echar un vistazo a un artículo que he escrito para encontrar más formas de usar las propiedades de Python.

 6
Author: nvd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-12 23:14:46

Haría una clase que anula el método __setattr__ de la clase de objeto base y envolver mis constantes con eso, tenga en cuenta que estoy usando 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)

Para envolver una cadena:

>>> 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'

Es bastante simple, pero si desea usar sus constantes de la misma manera que lo haría con un objeto no constante (sin usar constObj.valor), será un poco más intensivo. Es posible que esto podría causar problemas, por lo que podría ser mejor mantener el .value para mostrar y saber que está haciendo operaciones con constantes (quizás no la forma más 'pitónica').

 4
Author: Raufio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-10 00:09:10

Desafortunadamente, Python no tiene constantes todavía y es una vergüenza. ES6 ya ha añadido constantes de soporte a JavaScript ( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/const ) ya que es una cosa muy útil en cualquier lenguaje de programación. Como se respondió en otras respuestas en la comunidad Python, use la variable en mayúsculas convention - user como constantes, pero no protege contra errores arbitrarios en el código. Si lo desea, puede serle útil un solo archivo solución como siguiente (ver docstrings cómo usarlo).

Archivo 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 esto no es suficiente, consulte testcase completo para ello.

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"})

Ventajas: 1. Acceso a todas las constantes para todo el proyecto 2. Control estricto de los valores de constantes

Carece: 1. No es compatible con tipos personalizados y el tipo'dict'

Notas:

  1. Probado con Python3.4 y Python3. 5 (Estoy usando el 'tox' para ello)

  2. Pruebas medio ambiente:

.

$ 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
Author: Seti Volkylany,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-06 01:09:13

La forma pitónica de declarar "constantes" es básicamente una variable de nivel de módulo:

RED = 1
GREEN = 2
BLUE = 3

Y luego escribe tus clases o funciones. Dado que las constantes son casi siempre enteros, y también son inmutables en Python, tienes muy pocas posibilidades de alterarlo.

A menos que, por supuesto, establezca explícitamente RED = 2.

 3
Author: Xavier Ho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-21 13:28:28

Una tupla técnicamente califica como una constante, ya que una tupla generará un error si intenta cambiar uno de sus valores. Si desea declarar una tupla con un valor, coloque una coma después de su único valor, de esta manera:

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

Para verificar el valor de esta variable, use algo similar a esto:

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

Si intenta cambiar este valor, se generará un error.

 3
Author: tobahhh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-09 21:51:12

Puede usar un namedtuple como solución alternativa para crear efectivamente una constante que funcione de la misma manera que una variable final estática en Java (una "constante"de Java). Como solución alternativa, es algo elegante. (Un enfoque más elegante sería simplemente mejorar el lenguaje Python - - - ¿qué tipo de lenguaje le permite redefinir math.pi? -- pero estoy divagando.)

(Mientras escribo esto, me doy cuenta de otra respuesta a esta pregunta mencionada namedtuple, pero continuaré aquí porque mostraré una sintaxis que es más parecido a lo que esperarías en Java, ya que no hay necesidad de crear un tipo con nombre como namedtuple te obliga a hacerlo.)

Siguiendo tu ejemplo, recordarás que en Java debemos definir la constante dentro de alguna clase; como no mencionaste un nombre de clase, llamémosla Foo. Aquí está la clase Java:

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

Aquí está el equivalente Python.

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

El punto clave que quiero agregar aquí es que no necesita un tipo Foo separado (una "tupla con nombre anónimo" estaría bien, aunque eso suena como un oxímoron), así que nombramos nuestro namedtuple _Foo para que esperemos que no escape a la importación de módulos.

El segundo punto aquí es que creamos inmediatamente una instancia del nametuple, llamándolo Foo; no hay necesidad de hacer esto en un paso separado (a menos que lo desee). Ahora puedes hacer lo que puedes hacer en Java:

>>> Foo.CONST_NAME
'Name'

Pero no puedes asignarle: {[14]]}

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

Reconocimiento: I pensé que inventé el enfoque namedtuple, pero luego veo que alguien más dio una respuesta similar (aunque menos compacta). Entonces también noté ¿Qué son las "tuplas con nombre" en Python?, que señala que sys.version_info ahora es un namedtuple, por lo que tal vez la biblioteca estándar de Python ya se le ocurrió esta idea mucho antes.

Tenga en cuenta que desafortunadamente (esto sigue siendo Python), puede borrar toda la asignación Foo en conjunto:

>>> Foo = 'bar'

(facepalm)

Pero al menos estamos evitando que el valor Foo.CONST_NAME se cambie, y eso es mejor que nada. Buena suerte.

 3
Author: Garret Wilson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:47

Los diccionarios Python son mutables, por lo que no parecen una buena manera de declarar constantes:

>>> constants = {"foo":1, "bar":2}
>>> print constants
{'foo': 1, 'bar': 2}
>>> constants["bar"] = 3
>>> print constants
{'foo': 1, 'bar': 3}
 2
Author: n8boyd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-30 07:36:28

En python, una constante es simplemente una variable con un nombre en todas las mayúsculas, con palabras separadas por el carácter de subrayado,

E. g

DAYS_IN_WEEK = 7

El valor es mutable, ya que puede cambiarlo. Pero dadas las reglas para que el nombre te diga que es una constante, ¿por qué lo harías? Quiero decir, es su programa después de todo!

Este es el enfoque adoptado en python. No hay una palabra clave private por la misma razón. Prefije el nombre con un subrayado y lo sabes está destinado a ser privado. El código puede romper la regla....al igual que un programador podría eliminar la palabra clave privada de todos modos.

Python podría haber añadido una palabra clave const... pero un programador podría eliminar la palabra clave y luego cambiar la constante si lo desea, pero ¿por qué hacer eso? Si quieres romper la regla, podrías cambiarla de todos modos. Pero ¿por qué molestarse en romper la regla si el nombre deja clara la intención?

Tal vez hay alguna prueba unitaria donde tiene sentido aplicar un cambio a ¿valor? Para ver lo que sucede para una semana de 8 días a pesar de que en el mundo real el número de días de la semana no se puede cambiar. Si el idioma te impidió hacer una excepción si solo hay este caso, necesitas romper la regla...entonces tendrías que dejar de declarar como una constante, aunque todavía es una constante en la aplicación, y no es este un caso de prueba que ve lo que sucede si se cambia.

El nombre en mayúsculas le dice que está destinado a ser un constante. Eso es lo importante. No es un lenguaje que imponga restricciones en el código que tenga el poder de cambiar de todos modos.

Esa es la filosofía de python.

 2
Author: innov8,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-30 12:14:53

Simplemente puedes:

STRING_CONSTANT = "hi"
NUMBER_CONSTANT = 89

Esperanza que hace todo mucho más simple

 2
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-06 09:15:39

En mi caso, necesitaba bytearrays inmutables para una implementación de una biblioteca criptográfica que contenía muchos números literales que quería garantizar que fueran constantes.

Esta respuesta funciona, pero el intento de reasignación de elementos bytearray no genera un error.

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

Las constantes son inmutables, pero la asignación constante de bytearray falla silenciosamente:

>>> 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 enfoque más poderoso, simple y quizás aún más 'pitónico' implica el uso de objetos memoryview (buffer objetos en

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)

La asignación de elementos ConstArray es un 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
Author: jxqz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-25 16:37:03

Escribo una lib útil para python const: kkconst-pypi soporte str, int, float, datetime

La instancia const field mantendrá su comportamiento de tipo base.

Por ejemplo:

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

Más detalles uso puedes leer la url pypi: pypi o github

 1
Author: kaka_ace,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-23 10:49:59

Puede envolver una constante en una matriz numpy, marcarla solo escribir y siempre llamarla por índice cero.

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

Por supuesto, esto solo protege el contenido del numpy, no la variable "CONSTANTE" en sí; todavía puede hacer:

CONSTANT = 'foo'

Y CONSTANT cambiarían, sin embargo eso lanzaría rápidamente un TypeError la primera vez que CONSTANT[0] se llama más tarde en el script.

Aunque... Supongo que si en algún momento lo cambiaste a

CONSTANT = [1,2,3]

Ahora no obtendrías el TypeError nunca más. hmmmm....

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

 1
Author: litepresence,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-01 04:25:37

Podemos crear un objeto descriptor:

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
Author: MVP,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-12 15:57:09

Aquí hay un truco si quieres constantes y no te importan sus valores:

Simplemente defina clases vacías.

Ej:

class RED: 
    pass
class BLUE: 
    pass
 1
Author: Lym Zoy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-11 07:03:36

Puede usar StringVar o IntVar, etc, su constante es const_val

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

def reverse(*args):
    const_val.set(val)
 1
Author: Nqobizwe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-30 08:53:48

En Python, las constantes no existen. Pero puede indicar que una variable es una constante y no debe cambiarse agregando '_CONSTANT' al comienzo del nombre de la variable, nombrando la variable en MAYÚSCULAS y agregando un comentario usando el hashtag (' # ') e. g.:

    normal_variable = 0
    CONSTANT_variable = 1    # This is a constant - do not change its value!   
 1
Author: Aryan Beezadhur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-14 20:03:45

Extendiendo la respuesta de Raufio, agregue un repr para devolver el valor.

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

Entonces el objeto se comporta un poco más como se podría esperar, se puede acceder directamente en lugar de'.valor'

 0
Author: Jonathan Kimball Galloway,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-26 15:10:23

Bueno.. a pesar de que esto es anticuado, permítanme añadir mis 2 centavos aquí: -)

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)

En lugar de que se rompa ValueError, puede evitar que se produzca cualquier actualización allí. Una ventaja de esto es que puede agregar constantes dinámicamente en el programa, pero no puede cambiar una vez que se establece una constante. También puede agregar cualquier regla o lo que sea antes de establecer una constante (algo como key debe ser una cadena o una cadena minúscula o cadena mayúscula y así sucesivamente antes de establecer la clave)

Sin embargo, sí no veo ninguna importancia de establecer constantes en Python. No hay optimizaciones pueden suceder como en C y por lo tanto es algo que no se requiere, supongo.

 0
Author: thiruvenkadam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-20 13:03:28

Puede emular variables constantes con la ayuda de la siguiente clase. Un ejemplo de uso:

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

Llame al constructor cuando desee iniciar un nuevo espacio de nombres constante. Tenga en cuenta que la clase está bajo protección de constantes de tipo de secuencia de modificación inesperada cuando la clase de Martelli const no lo está.

La fuente está abajo.

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
Author: sergzach,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-27 16:36:11

No hay una manera perfecta de hacer esto. Como yo lo entiendo, la mayoría de los programadores simplemente capitalizarán el identificador, por lo que PI = 3.142 puede entenderse fácilmente como una constante.

Por otro lado, si quieres algo que realmente actúe como una constante, no estoy seguro de que lo encuentres. Con cualquier cosa que hagas siempre habrá alguna forma de editar la "constante" para que realmente no sea una constante. He aquí un ejemplo muy simple y sucio:

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"))

Esto parece que hará un estilo PHP constante.

En realidad todo lo que se necesita para que alguien cambie el valor es esto:

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

Esto es lo mismo para todas las otras soluciones que encontrará aquí, incluso las inteligentes que crean una clase y redefinen el método de atributo set, siempre habrá una forma de evitarlas. Así es Python.

Mi recomendación es simplemente evitar toda la molestia y simplemente capitalizar sus identificadores. Realmente no sería una constante adecuada, pero de nuevo nada lo sería.

 0
Author: John,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-23 14:02:11

(Este párrafo estaba destinado a ser un comentario sobre esas respuestas aquí y allí, que mencionaban namedtuple, pero se está volviendo demasiado largo para encajar en un comentario, así que aquí va.)

El enfoque namedtuple mencionado anteriormente es definitivamente innovador. En aras de la exhaustividad, sin embargo, al final de la sección NamedTuple de su documentación oficial, dice:

Las constantes enumeradas se pueden implementar con tuplas nombradas, pero es más simple y más eficiente para usar una declaración de clase simple:

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

En otras palabras, la documentación oficial prefiere usar una forma práctica, en lugar de implementar realmente el comportamiento de solo lectura. Supongo que se convierte en otro ejemplo de Zen de Python :

Simple es mejor que complejo.

La practicidad vence a la pureza.

 0
Author: RayLuo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-06 00:05:43

Hay una forma más limpia de hacer esto con namedtuple:

from collections import namedtuple


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

Ejemplo de uso

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

Con este enfoque exacto puede hacer espacio de nombres de sus constantes.

 0
Author: Juan Ignacio Sánchez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-13 05:01:01