python常量 - python类中的常量

如何在Python中创建常量? (19)

有没有办法在Python中声明一个常量? 在Java中,我们可以用这种方式创建常量值:

public static final String CONST_NAME = "Name";


In Python, constants do not exist. But you can indicate that a variable is a constant and must not be changed by adding ' _CONSTANT ' to the start of the variable name, naming the variable in BLOCK CAPITALS, and adding a comment using the hashtag (' # ') eg :

    normal_variable = 0
    CONSTANT_variable = 1    # This is a constant - do not change its value!   


RED = 1
BLUE = 3

然后编写你的类或函数。 由于常量几乎总是整数,并且它们在Python中也是不可变的,所以您很少有机会改变它。

当然,除非你明确设定RED = 2

Extending Raufio's answer, add a repr to return the value.

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

then the object behaves a little more like you might expect, you can access it directly rather then '.value'

Here's a trick if you want constants and don't care their values:

Just define empty classes.


class RED: 
class BLUE: 

We can create a descriptor object:

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

You can emulate constant variables with help of the next class. An example of usage:

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

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


print 'const.four: ', const.four

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


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


Call the constructor when you want to start a new constant namespace. Note that the class is under protection from unexpected modifying sequence type constants when Martelli's const class is not.

The source is below.

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


    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)


my_consts={"TIMEOUT":300, "RETRIES":10, "STATE":"happy"}

if i > my_consts["TIMEOUT"]:
  print "I've just timed out. Sorry folks."
  print "I tried, many times, " + str(my_consts["RETRIES"]) + " in fact."
  print "But I am still feeling quite " + my_consts["STATE"]

well.. even though this is outdated, let me add my 2 cents here :-)

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)

Instead of ValueError to break, you can prevent any update happening there. One advantage of this is that you can add constants dynamically in the program but you cannot change once a constant is set. Also you can add any rule or whatsoever before setting a constant(something like key must be a string or a lower case string or upper case string and so on before setting the key)

However, I do not see any importance of setting constants in Python. No optimizations can happen like in C and hence it is something that is not required, I guess.

不幸的是,Python还没有常量,这是令人遗憾的。 ES6已经将支持常量添加到JavaScript( ),因为它在任何编程语言中都是非常有用的。 正如在Python社区中的其他答案中回答的那样,使用惯例 - 用户大写变量作为常量,但它不能防止代码中的任意错误。 如果你愿意,你可能会发现下一个单文件解决方案很有用(请参阅docstrings如何使用它)。


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


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,, [], {}]
        self.assertEqual(self.const.LIST, (1, .2, None, True,, [], {}))

        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,, [], {})
        self.assertEqual(self.const.TUPLE, (1, .2, None, True,, [], {}))

        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,}
        self.assertEqual(self.const.SET, {1, .2, None, True,})

        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,})
        self.assertEqual(self.const.FROZENSET, frozenset({1, .2, None, True,}))

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

    def test_create_and_change_date_constant(self):

        self.const.DATE =, 11, 11)
        self.assertEqual(self.const.DATE,, 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"})




  1. 使用Python3.4和Python3.5进行测试(我使用'tox')

  2. 测试环境:

$ 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

不,那里没有。 您不能在Python中将变量或值声明为常量。 只是不要改变它。


class Foo(object):
    CONST_NAME = "Name"



但你可能想看看由Alex Martelli编写的Python中的代码段常量

元组在技术上属于常量,因为如果尝试更改其中一个值,元组将会引发错误。 如果你想用一个值声明一个元组,那么在它的唯一值之后放置一个逗号,如下所示:

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


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






    return "one"

只有问题是无处不在,你将不得不做MY_CONSTANT(),但MY_CONSTANT = "one"是Python中的正确方式(通常)。


>>> from collections import namedtuple
>>> Constants = namedtuple('Constants', ['pi', 'e'])
>>> constants = Constants(3.14, 2.718)
>>> constants.pi
>>> constants.pi = 3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute



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

        raise ConstError

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

    return property(fget, fset)

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

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

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


>>> c = Consts()
>>> c.pi = 6.283185307179586  # (
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "", line 9, in fset
    raise ConstError
>>> c.C1[0] = 0
>>> c.C1[0]
>>> c.C1

一个更强大,更简单,甚至更“pythonic”的方法涉及使用memoryview对象(<= 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'))
            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)


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

属性是创建常量的一种方法。 你可以通过声明一个getter属性来完成,但忽略setter。 例如:

class MyFinalProperty(object):

    def name(self):
        return "John"


我为python const编写了一个util lib: kkconst - pypi支持str,int,float,datetime



from __future__ import print_function
from kkconst import (

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

更多的细节用法,你可以阅读pypi url: pypi或者github


class CONST(object):
    FOO = 1234

    def __setattr__(self, *_):



print CONST.FOO    # 1234

CONST.FOO = 4321
CONST.BAR = 5678

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

创建实例允许魔法__setattr__方法启动并拦截尝试设置FOO变量。 如果你愿意,你可以在这里抛出异常。 通过类名实例化实例可防止直接通过类访问。

对于一个价值来说,这是一种痛苦,但是你可以将很多东西附加到你的CONST对象上。 拥有一个上层阶级,阶级名称也似乎有点糟糕,但我认为这是相当简洁的整体。


也许最简单的选择是为它定义一个函数。 例如

    return 42


编辑:添加Python 3的示例代码

注意: 这个答案看起来像它提供了一个更完整的实现类似于以下(具有更多的功能)。

首先,创建一个metaclass :

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

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

这可以防止更改静态属性。 然后创建另一个使用该元类的类:

class Const(object):
    __metaclass__ = MetaConst

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

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

或者,如果您使用Python 3:

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

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

这应该防止实例道具被更改。 要使用它,继承:

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


# 1
my_const = MyConst()
# 1

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

Here's是上面Here's一个例子。 Here's Python 3 Here's另一个例子。

import collections
import itertools
def Constants(Name, *Args, **Kwargs):
  t = collections.namedtuple(Name, itertools.chain(Args, Kwargs.keys()))
  return t(*itertools.chain(Args, Kwargs.values()))

>>> myConstants = Constants('MyConstants', 'One', 'Two', Three = 'Four')
>>> print myConstants.One
>>> print myConstants.Two
>>> print myConstants.Three
>>> myConstants.One = 'Two'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute