如何在Python中创建常量?

1366

在Python中如何声明常量?

在Java中,我们这样做:

public static final String CONST_NAME = "Name";

11
在Python中,通过使用property函数/装饰器,可以实现将变量设置为只读。inv答案是它的一个自定义用例示例。虽然property函数更具有通用性,但关于它的工作原理的良好分析可在Shalabh Chaturvedi的Python Attributes and Methods网站上找到。 - n611x007
35
在我看来,强制使用常量 "不符合 Python 的风格"。在 Python 2.7 中,甚至可以编写 True=False,然后 (2+2==4)==True 将返回 False - Sergey Orshanskiy
8
正如其他答案所建议的那样,没有必要或者说没有办法去声明常量。但是你可以阅读这个PEP来了解惯例。例如:THIS_IS_A_CONSTANT。 - Govinnage Rasika Perera
51
@osa: 在 Python 3 中你不能这样做 - SyntaxError: can't assign to keyword。这看起来是一件好事。 - naught101
10
直到现在都没有提到,但是枚举似乎是定义枚举常量的一种好方式。 - cs95
显示剩余2条评论
44个回答

13
from enum import Enum
class StringConsts(str,Enum):
    ONE='one'
    TWO='two'

print(f'Truth is  {StringConsts.ONE=="one"}') #Truth is True
StringConsts.ONE="one" #Error: Cannot reassign

这个枚举和字符串的混合体赋予您的能力,使您无需重新实现 setattr(通过枚举)并可以与其他字符串对象进行比较(通过字符串)。

这可能会完全废弃http://code.activestate.com/recipes/65207-constants-in-python/?in=user-97991


请注意,这个问题已经有一个被接受的答案了。请[编辑]您的答案,以确保它能够改进已经存在于此问题中的其他答案。 - hongsy
3
其他答案要么重新实现set_attr,要么存在在代码库的任何地方意外赋值的缺点。没有其他答案提到Enum,更不用说将Enum和str混合使用的mixin了。 - yoni keren
4
到目前为止,这是最好的答案。使用实数常量,没有自定义类,语法简洁。一些答案使用属性,这很不错,但并不适用于所有情况。例如,如果您希望具有可以按位或的 int 值,则使用属性会出现错误。对于枚举,您只需使用 IntFlag 变体即可使其正常工作。 - acapola

12
您可以使用namedtuple作为解决方法,有效地创建一个与Java中的静态final变量(Java“常量”)相同的常量。作为解决方法,它有一定的优雅性。(更加优雅的方法是简单地改进Python语言 --- 什么样的语言让您重新定义math.pi?--但我偏离了主题。)
(当我写这篇文章时,我意识到这个问题的另一个答案提到了namedtuple,但我会继续在这里,因为我将展示一个更接近Java预期的语法,因为没有必要像namedtuple强制您这样做,创建一个命名类型。)
按照您的示例,您会记得在Java中我们必须在某个类内定义常量;因为您没有提到类名,让我们称其为Foo。以下是Java类:
public class Foo {
  public static final String CONST_NAME = "Name";
}

这里是相应的Python代码。
from collections import namedtuple
Foo = namedtuple('_Foo', 'CONST_NAME')('Name')

我要补充的关键点是,你不需要一个单独的Foo类型(即使听起来像个矛盾的词组"匿名命名元组"也很好),因此我们将我们的命名元组命名为_Foo,希望它不会逃逸到导入模块中。
第二个要点是,我们立即创建nametuple的实例,称之为Foo;没有必要分成两步来做(除非你想这么做)。现在你可以像Java一样做的事情了:
>>> Foo.CONST_NAME
'Name'

但你不能给它赋值:

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

致谢:我曾以为自己发明了namedtuple的方法,但后来发现有人给出了类似的答案(虽然不够简洁)。之后我还注意到了Python中的“命名元组”是什么?,它指出sys.version_info现在是一个namedtuple,因此Python标准库可能早在很久以前就已经想出了这个想法。
请注意,不幸的是(这仍然是Python),您可以完全删除Foo赋值:
>>> Foo = 'bar'

但至少我们防止了Foo.CONST_NAME值的更改,这总比什么都不做要好。 祝好运。

(面对掌声)


9

元组在技术上可以被视为常量,因为如果你试图改变其中一个值,它会引发错误。如果你想声明一个只有一个值的元组,则需要在该值后面加上逗号,像这样:

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

要检查此变量的值,请使用类似以下内容的代码:

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

如果你试图更改这个值,将会引发错误。


9
这里是一个“常量”类的实现,创建了只读(常量)属性的实例。例如,可以使用 Nums.PI 来获取已初始化为 3.14159 的值,而 Nums.PI = 22 将会引发异常。
# ---------- 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

感谢@MikeGraham的FrozenDict,我以此为起点。 修改后,使用语法为Nums.ONE,而不是Nums['ONE']

还要感谢@Raufio的答案,因为他的想法覆盖了__setattr__方法。

或者,如果需要更多功能的实现,请参见@Hans_meine在GitHub上的named_constants


3
Python是一门自由开放的语言,不会对这样的操作进行保护:Nums._d['PI'] = 22。我认为这门语言本身并没有提供将某物标记为不可变的方法。 - Ajay M
1
作为初学者的Python和Haskell开发人员,我不认为我会很快尝试Nums._d['PI'] = 22。有时,不可变性的目的是防止我自己犯错。我喜欢具有安全开关的语言,例如C/C++/Haskell,但仍然允许我在需要时犯错。人们经常不认为C/C++是安全的语言,但至少它们有非常强大的const关键字。 - Shawn Eary

8

这里是我创作的一些成语集合,旨在改进已有答案。

我知道使用常量不符合Python风格,你不应该在家里这么做!

然而,Python是一门如此动态的语言!这个论坛展示了如何创建看起来感觉像常量的结构。这篇答案的主要目的是探索语言可以表达的内容。

请不要对我太严厉 :-)。

更多细节我写了一篇有关这些惯用语的博客

在本文中,我将称常量变量为常量值(不可变或可变)。此外,当一个变量引用一个客户端代码无法更新其值的可变对象时,我称它具有冻结值。

常量空间(SpaceConstants)

这个成语创建了一个看起来像常量变量命名空间(也称SpaceConstants)的东西。它是Alex Martelli代码片段的修改版,以避免使用模块对象。特别地,在SpaceConstants函数内部,定义了一个名为SpaceConstants的类,并返回其实例,因此采用了我所说的类工厂。
我在stackoverflow和一篇blogpost中探索了使用类工厂在Python中实现类似于基于策略的设计的外观。
def SpaceConstants():
    def setattr(self, name, value):
        if hasattr(self, name):
            raise AttributeError(
                "Cannot reassign members"
            )
        self.__dict__[name] = value
    cls = type('SpaceConstants', (), {
        '__setattr__': setattr
    })
    return cls()

sc = SpaceConstants()

print(sc.x) # raise "AttributeError: 'SpaceConstants' object has no attribute 'x'"
sc.x = 2 # bind attribute x
print(sc.x) # print "2"
sc.x = 3 # raise "AttributeError: Cannot reassign members"
sc.y = {'name': 'y', 'value': 2} # bind attribute y
print(sc.y) # print "{'name': 'y', 'value': 2}"
sc.y['name'] = 'yprime' # mutable object can be changed
print(sc.y) # print "{'name': 'yprime', 'value': 2}"
sc.y = {} # raise "AttributeError: Cannot reassign members"

冻结值的空间(SpaceFrozenValues)

这个惯用语是对 SpaceConstants 的修改,其中引用的可变对象被冻结。此实现利用我所谓的 setattr getattr 函数之间的共享闭包。可变对象的值被复制并由在函数共享闭包内定义的变量 cache 引用。它形成了我所说的受闭包保护的可变对象副本

在使用此习语时必须小心,因为 getattr 通过进行深层复制来返回cache的值。这种操作可能会对大型对象产生重大的性能影响!

from copy import deepcopy

def SpaceFrozenValues():
    cache = {}
    def setattr(self, name, value):
        nonlocal cache
        if name in cache:
            raise AttributeError(
                "Cannot reassign members"
            )
        cache[name] = deepcopy(value)
    def getattr(self, name):
        nonlocal cache
        if name not in cache:
            raise AttributeError(
                "Object has no attribute '{}'".format(name)
            )
        return deepcopy(cache[name])
    cls = type('SpaceFrozenValues', (),{
        '__getattr__': getattr,
        '__setattr__': setattr
    })
    return cls()

fv = SpaceFrozenValues()
print(fv.x) # AttributeError: Object has no attribute 'x'
fv.x = 2 # bind attribute x
print(fv.x) # print "2"
fv.x = 3 # raise "AttributeError: Cannot reassign members"
fv.y = {'name': 'y', 'value': 2} # bind attribute y
print(fv.y) # print "{'name': 'y', 'value': 2}"
fv.y['name'] = 'yprime' # you can try to change mutable objects
print(fv.y) # print "{'name': 'y', 'value': 2}"
fv.y = {} # raise "AttributeError: Cannot reassign members"

常量空间(ConstantSpace)

这个习语是一个不可变的常量变量或常量空间的命名空间。它是Jon Betts在stackoverflow的简单回答与class factory结合的结果。

def ConstantSpace(**args):
    args['__slots__'] = ()
    cls = type('ConstantSpace', (), args)
    return cls()

cs = ConstantSpace(
    x = 2,
    y = {'name': 'y', 'value': 2}
)

print(cs.x) # print "2"
cs.x = 3 # raise "AttributeError: 'ConstantSpace' object attribute 'x' is read-only"
print(cs.y) # print "{'name': 'y', 'value': 2}"
cs.y['name'] = 'yprime' # mutable object can be changed
print(cs.y) # print "{'name': 'yprime', 'value': 2}"
cs.y = {} # raise "AttributeError: 'ConstantSpace' object attribute 'x' is read-only"
cs.z = 3 # raise "AttributeError: 'ConstantSpace' object has no attribute 'z'"

一个冰冻的空间(FrozenSpace)

这个习语是指一组不可变的变量或FrozenSpace命名空间。它源于先前的模式,通过将每个变量作为生成的FrozenSpace类的闭包受保护的属性来实现。

from copy import deepcopy

def FreezeProperty(value):
    cache = deepcopy(value)
    return property(
        lambda self: deepcopy(cache)
    )

def FrozenSpace(**args):
    args = {k: FreezeProperty(v) for k, v in args.items()}
    args['__slots__'] = ()
    cls = type('FrozenSpace', (), args)
    return cls()

fs = FrozenSpace(
    x = 2,
    y = {'name': 'y', 'value': 2}
)

print(fs.x) # print "2"
fs.x = 3 # raise "AttributeError: 'FrozenSpace' object attribute 'x' is read-only"
print(fs.y) # print "{'name': 'y', 'value': 2}"
fs.y['name'] = 'yprime' # try to change mutable object
print(fs.y) # print "{'name': 'y', 'value': 2}"
fs.y = {} # raise "AttributeError: 'FrozenSpace' object attribute 'x' is read-only"
fs.z = 3 # raise "AttributeError: 'FrozenSpace' object has no attribute 'z'"

8
我们可以创建一个描述符对象。
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")

1) 如果我们想在实例级别上使用常量,那么:

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

如果我们只想在类级别上创建常量,我们可以使用元类作为常量的容器(即描述符对象);所有继承它的类都会继承这些常量并且不会被修改。
# metaclass of my class Foo
class FooMeta(type): pass

# class Foo
class Foo(metaclass=FooMeta): pass

# I create constants in my metaclass
FooMeta.NUM = Constant(0xff)
FooMeta.NAME = Constant('FOO')

>>> Foo.NUM   #=> 255
>>> Foo.NAME  #=> 'FOO'
>>> Foo.NUM = 0 #=> ValueError: You can't change a constant

如果我创建Foo的子类,那么这个类将继承常量而无法修改它们。
class Bar(Foo): pass

>>> Bar.NUM  #=> 255
>>> Bar.NUM = 0  #=> ValueError: You can't change a constant

点赞这个回答是因为它实际上解决了原问题中的“静态”组件,并提供了一种使用元类声明基于类的常量的简洁方法,而不是像其他答案中那样使用实例级别的常量。对我来说更有意义。 - Dmytro Bugayev

7

我会创建一个类,覆盖基本对象类的__setattr__方法,并将我的常量包装在其中,注意我使用的是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)

将字符串包装起来:

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

这很简单,但如果您想像非常量对象一样使用常量(而不使用constObj.value),那么它会更加复杂。这可能会导致问题,因此最好保留.value以显示并知道您正在使用常量进行操作(虽然这可能不是最符合Python风格的方法)。


有趣的方法,点赞。虽然不如已经提供的答案干净,甚至比最简单的早期建议的解决方案“def ONE(): return 1”更容易使用“ONE()”,而不是这个答案“ONE.value”。 - ToolmakerSteve

7

很遗憾,Python目前还没有常量,这是一件令人惋惜的事情。ES6已经在JavaScript中添加了对常量的支持(https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/const),因为在任何编程语言中都是非常有用的东西。

正如其他答案中所回答的,在Python社区中使用大写字母变量作为常量的约定,但这并不能防止代码中出现任意错误。

如果您愿意,您可以找到一个单文件解决方案,如下所示(请查看文档字符串以了解如何使用它)。

文件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()

如果这还不够,请查看完整的测试用例。
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"})

优点: 1. 可以访问整个项目的所有常量。 2. 对常量值有严格的控制。

缺点: 1. 不支持自定义类型和'type'为'dict'的类型。

备注:

  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

你可以通过自动将字典转换为命名元组来稍微改进这个。 - Peter Schorn

6

使用namedtuple可以更简洁地实现这个功能:

from collections import namedtuple


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

使用示例

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

通过这种方法,您可以对常量进行命名空间管理。


对于所有阅读此内容的人,请记住,如果您将可变对象设置为这些常量之一,任何人都可以更改其内部值。例如,让我们设bar=[1, 2, 3],那么,您可以执行以下操作:CONSTS.bar[1] = 'a',它不会被拒绝。因此,请小心处理此类情况。 - Juan Ignacio Sánchez
不要使用我为了好玩而制作的这种笨拙方法,我建议使用Python的属性装饰器。 - Juan Ignacio Sánchez

6

在Python中声明“常量”的方式基本上是一个模块级变量:

RED = 1
GREEN = 2
BLUE = 3

然后编写你的类或函数。由于常量几乎总是整数,并且在Python中它们也是不可变的,因此你很少有机会对其进行更改。

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


27
是的,但是阻止能够“明确设置RED = 2”的能力,是将变量名声明为“常量”的整个好处(在其他语言中)! - ToolmakerSteve
6
阻止那个会给你带来什么好处?在const中最有用的事情通常是编译器优化,而在Python中并没有这个东西。想让某些东西保持不变吗?就不要去改变它。如果你担心别人会去改变它,你可以把它放在他们的作用域之外,或者认识到,如果有人改变它,那是他们的问题,他们需要自己处理,而不是你。 - Kevin
@Kevin: “你会得到什么好处…”,使用static关键字的好处是为类的所有实例提供单一的存储空间,除非确实有声明静态/类变量的可能性。 - mins
8
根本问题在于有些人可能将其视为一种真理的价值观,无法更改,并将其用作他们代码中的真理来源,而不是引入魔术值(我在 Python 中看到了很多这样的情况),而另一些人则认为它是可以随意更改的。当有人更改全局变量,并且你无法确定它在哪里被更改时,应用程序会崩溃,因为 RED =“blue”而不是“red”,这就引入了一个完全不必要的问题,而这个问题已经被如此简单地解决,并且是普遍理解的。 - Dagrooms
2
阻止它会给你带来什么好处?” 这是 Pythonic 的回答语言怪异之处的方式:你应该永远不犯错误,那么为什么要添加限制呢?为什么要像其他语言一样在块周围添加括号?你只需要永远不要误删一个制表符。这就是好程序员所做的。如果你不能做到,那么你不是一个好的程序员,你应该使用 Java。拥有常量的明显优点是您的代码检查器将能够告诉您当您尝试将值分配给常量时(代码检查器被不好的程序员使用)。 - mins

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接