如何在Python中创建常量?

How do I create a constant in Python?

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

1
public static final String CONST_NAME ="Name";

与Python中的Java常量声明等价的是什么?


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

如果你在一个班级里,相当于:

1
2
class Foo(object):
    CONST_NAME ="Name"

如果不是,那只是

1
CONST_NAME ="Name"

但您可能想看看AlexMartelli在python中的代码片段常量。


在其他语言中没有const关键字,但是可以创建一个具有"getter函数"来读取数据,但没有"setter函数"来重新写入数据的属性。这从本质上保护了标识符不被更改。

下面是一个使用类属性的替代实现:

请注意,对于一个对常量感到好奇的读者来说,这段代码并不容易。见下文解释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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

代码说明:

  • 定义一个接受表达式的函数constant,并使用它来构造一个"getter"——一个只返回表达式值的函数。
  • setter函数引发一个typeerror,因此它是只读的
  • 使用我们刚刚创建的作为装饰的constant函数来快速定义只读属性。
  • 还有一些更传统的方式:

    (代码相当复杂,下面有更多解释)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    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

    请注意,@apply decorator似乎已被弃用。

  • 要定义标识符foo,firs定义两个函数(fset、fget-名称由我选择)。
  • 然后使用内置的property函数构造一个可以"set"或"get"的对象。
  • 注意,property函数的前两个参数分别命名为fsetfget
  • 使用我们为自己的getter&setter选择这些名称的事实,并使用应用于该作用域的所有本地定义的**(双星号)创建关键字字典,以将参数传递给property函数。

  • 在python中,人们使用命名约定,如__method来表示私有方法,使用_method来表示受保护的方法,而不是强制语言。

    因此,以同样的方式,您可以简单地将常量声明为所有caps,例如

    1
    MY_CONSTANT ="one"

    如果您希望这个常量永远不会改变,您可以钩住属性访问并做一些技巧,但是更简单的方法是声明一个函数

    1
    2
    def MY_CONSTANT():
        return"one"

    唯一的问题是,在任何地方,您都必须执行my_constant(),但同样,MY_CONSTANT ="one"是Python中的正确方法(通常)。

    还可以使用NamedDuple创建常量:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    >>> 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


    我最近发现了一个非常简洁的更新,它自动产生有意义的错误消息,并阻止通过__dict__访问:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class CONST(object):
        __slots__ = ()
        FOO = 1234

    CONST = CONST()

    # ----------

    print(CONST.FOO)    # 1234

    CONST.FOO = 4321              # AttributeError: 'CONST' object attribute 'FOO' is read-only
    CONST.__dict__['FOO'] = 4321  # AttributeError: 'CONST' object has no attribute '__dict__'
    CONST.BAR = 5678              # AttributeError: 'CONST' object has no attribute 'BAR'

    我们将自己定义为使自己成为一个实例,然后使用槽来确保不能添加其他属性。这还删除了__dict__访问路由。当然,整个对象仍然可以重新定义。

    编辑-原始解决方案

    我可能错过了一个技巧,但这似乎对我有用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    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

    创建实例允许magic __setattr__方法启动并拦截设置FOO变量的尝试。如果你愿意的话,你可以在这里提出一个例外。在类名上实例化实例会阻止直接通过类访问。

    对于一个价值来说,这是一种痛苦,但是你可以在你的CONST对象上附加很多东西。有了上层阶级,类名也显得有点怪,但我觉得总体上它是相当简洁的。


    正如您可能已经知道的,python没有常量:(

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

    1
    2
    def MY_CONSTANT():
        return 42

    MY_CONSTANT()现在具有常量的所有功能(加上一些恼人的大括号)。


    除了两个最重要的答案(只使用大写名称的变量,或使用属性使值只读)之外,我还想提到,可以使用元类来实现命名常量。我在GitHub提供了一个使用元类的非常简单的解决方案,如果您希望这些值的类型/名称更具信息性,这可能会有所帮助:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    >>> 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

    这是稍微高级一点的python,但仍然非常容易使用和方便。(该模块还有一些其他功能,包括只读常量,请参阅自述文件。)

    在不同的存储库中也有类似的解决方案,但据我所知,它们要么缺乏我期望从常量中得到的基本特性之一(如常量或任意类型),要么它们添加了一些使它们不那么普遍适用的深奥特性。但是Ymmv,我很感谢你的反馈。-)


    编辑:为python 3添加了示例代码

    注意:另一个答案似乎提供了一个更完整的实现,类似于以下内容(具有更多特性)。

    首先,创建元类:

    1
    2
    3
    4
    5
    6
    class MetaConst(type):
        def __getattr__(cls, key):
            return cls[key]

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    class Const(object):
        __metaclass__ = MetaConst

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

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

    或者,如果您使用的是python 3:

    1
    2
    3
    4
    5
    6
    class Const(object, metaclass=MetaConst):
        def __getattr__(self, name):
            return self[name]

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

    这将防止更改实例属性。要使用它,请继承:

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

    现在,直接或通过实例访问的属性应该是常量:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    MyConst.A
    # 1
    my_const = MyConst()
    my_const.A
    # 1

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

    下面是上面的一个例子。下面是Python3的另一个示例。


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

    1
    2
    3
    4
    5
    class MyFinalProperty(object):

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

    您可以看看我写的一篇文章,了解更多使用Python属性的方法。


    这里是一个"常量"类的实现,它创建具有只读(常量)属性的实例。例如,可以使用Nums.PI获取已初始化为3.14159的值,而Nums.PI = 22引发异常。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    # ---------- 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'sGithub的命名_常量


    不幸的是,python还没有常量,这是可耻的。ES6已经向javascript添加了支持常量(https://developer.mozilla.org/en/docs/web/javascript/reference/statements/const),因为它在任何编程语言中都是非常有用的。正如在Python社区的其他答案中所回答的那样,使用约定的用户大写变量作为常量,但它不能防止代码中的任意错误。如果您愿意的话,下一步您可能会发现使用单个文件解决方案很有用(参见docstrings如何使用它)。好的。

    文件常量.py好的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    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()

    如果这还不够,请参阅完整的测试用例。好的。

    1
    2
    3
    4
    5
    import decimal进口UUID导入日期时间进口统一测试From..常量导入常量类testconstant(unittest.testcase)""测试python中的实现常量""定义设置(自身)self.const=常量()定义拆卸(自行):德尔常数def test_用_-different_-variants_of_-name(self)创建_-constant_:self.const.常量=1self.assertequal(self.const.constant1)self.const.常量=2self.assertequal(self.const.constant2)self.const.常量=3self.assertequal(self.const.constant3)self.const.常量=4self.assertequal(self.const.constant4)self.const.co_ns_ta_nt=5Self.AssertEqual(self.const.co_n s_t,5)self.const.constant111=6self.assertequal(self.const.constant11116)def test_create_and_change_integer_常量(self)self.const.int=1234self.assertequal(self.const.int1234)使用self.assertraisesregexp(typeerror,"constanst can be changed")self.const.int=0.211def test_create_and_change_float_常量(self)self.const.float=0.1234self.assetmequal(self.const.float.1234)使用self.assertraisesregexp(typeerror,"constanst can be changed")self.const.float=0.211def 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.listtuple))。使用self.assertraisesregexp(typeerror,"constanst can be changed")self.const.list=0.211def test_create_and_change_none_常量(self)self.const.none=self.assertequal(self.const.none,无)使用self.assertraisesregexp(typeerror,"constanst can be changed")self.const.none=0.211def test_create_and_change_boolean_常量(self)self.const.boolean=self.assertEqual(self.const.boolean,true)使用self.assertraisesregexp(typeerror,"constanst can be changed")self.const.boolean=def test_create_and_change_string_constant(self)self.const.string="文本"self.assertEqual(self.const.string"文本")。使用self.assertraisesregexp(typeerror,"constanst can be changed")self.const.string+='...'使用self.assertraisesregexp(typeerror,"constanst can be changed")self.const.string='test1'def test_create_dict_constant(self):使用self.assertraisesregexp(typeerror,"dict不能用作常量")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()[])使用self.assertraisesregexp(typeerror,"constanst can be changed")self.const.tuple='测试1'def test_create_and_change_set_constant(self)self.const.set=1.2,none,true,datetime.date.today()self.assertEqual(self.const.set1.2,none,true,datetime.date.today())self.asserttrue(isInstance(self.const.setfrozenset))。使用self.assertraisesregexp(typeerror,"constanst can be changed")self.const.set=3212def test_create_and_change_frozenset_constant(self)self.const.frozenset=frozenset(1.2,none,true,datetime.date.today())self.assertEqual(self.const.frozensetfrozenset(1.2,none,true,datetime.date.today()))。使用self.assertraisesregexp(typeerror,"constanst can be changed")self.const.frozenset=def测试创建和更改日期常量(self)self.const.date=日期时间。日期(11111111)self.assertEqual(self.const.datedatetime.date(11111111))。使用self.assertraisesregexp(typeerror,"constanst can be changed")self.const.date=def test_create_and_change_datetime_常量(self)self.const.datetime=datetime.datetime(200010101010)self.assertEqual(self.const.datetimedatetime.datetime(20001010101010))。使用self.assertraisesregexp(typeerror,"constanst can be changed")self.const.datetime=def test_create_and_change_decimal_常量(self)self.const.decimal=十进制(13123.12312312321)self.assertequal(self.const.decimaldecimal.decimal(13123.12312312321))。使用self.assertraisesregexp(typeerror,"constanst can be changed")self.const.decimal=def test_create_and_change_timedelta_常量(self)self.const.timedelta=datetime.timedelta()=<hr><P>我将创建一个类来重写基本对象类的<wyn>__setattr__</wyn>方法,并用它包装我的常量,注意我使用的是python 2.7</P>[cc lang="python"]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)

    要包装字符串:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    >>> 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"的方式)。


    您可以使用NAMDUTUPLE作为一个解决方案来有效地创建一个常量,该常量与Java中的静态最终变量(Java常量)相同。随着解决方法的发展,它有点优雅。(更优雅的方法是简单地改进Python语言——什么样的语言可以让您重新定义math.pi?--但我离题了。)

    (在我写这篇文章的时候,我意识到这个问题的另一个答案是NordEtuple,但是我将继续这里,因为我将展示一个语法,它与Java中所期望的更贴近,因为不需要创建一个命名类型,NAMDUTPUE强迫你去做。)

    按照您的示例,您将记住,在Java中,我们必须在某些类中定义常量;因为您没有提到类名,我们称之为EDCOX1(1)。下面是Java类:

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

    这是等价的python。

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

    我想在这里补充的关键点是,您不需要单独的Foo类型(匿名命名的tuple很好,尽管听起来像一个矛盾修饰语),所以我们命名_Foo的名称,希望它不会逃过导入模块。

    这里的第二点是,我们立即创建一个命名元组的实例,称之为Foo;不需要在单独的步骤中进行此操作(除非您愿意)。现在你可以在爪哇做你能做的事情:

    1
    2
    >>> Foo.CONST_NAME
    'Name'

    但您不能分配给它:

    1
    2
    3
    >>> Foo.CONST_NAME = 'bar'

    AttributeError: can't set attribute

    承认:我以为我发明了名为双重的方法,但后来我发现有人给出了类似的(虽然不太紧凑)答案。然后我还注意到在Python中什么是"命名的元组"?它指出,sys.version_info现在是一个命名的副本,所以也许Python标准库早就提出了这个想法。

    请注意,不幸的是(这仍然是python),您可以完全删除整个Foo分配:

    1
    >>> Foo = 'bar'

    (FACEPALM)

    但至少我们在阻止Foo.CONST_NAME价值的改变,这比什么都没有要好。祝你好运。


    从技术上讲,元组被限定为一个常量,因为如果您试图更改其中一个值,则元组将引发错误。如果要声明一个具有一个值的元组,请在其唯一值后加一个逗号,如下所示:

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

    要检查此变量的值,请使用与此类似的内容:

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

    如果尝试更改此值,将引发错误。


    pythonic声明"常量"的方法基本上是一个模块级变量:

    1
    2
    3
    RED = 1
    GREEN = 2
    BLUE = 3

    然后编写类或函数。因为常量几乎总是整数,而且在Python中它们也是不可变的,所以修改它的可能性很小。

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


    在python中,常量只是一个以大写字母命名的变量,单词之间用下划线分隔,

    例如

    周天数=7

    值是可变的,正如您可以更改它一样。但是考虑到名字的规则告诉你是一个常数,你为什么要这样做?我是说,这毕竟是你的计划!

    这是贯穿整个Python的方法。由于同样的原因,没有private关键字。在名称前面加上下划线,您就知道它是私有的。代码可以打破规则……就像程序员可以删除私有关键字一样。

    python可以添加一个const关键字…但是程序员可以删除关键字,然后更改常量(如果他们愿意的话),但是为什么要这样做呢?如果你想打破规则,你可以改变规则。但是,如果这个名字让意图变得清晰,为什么还要打破这个规则呢?

    也许有一些单元测试,在其中应用对值的更改是有意义的?看看一周8天会发生什么,即使在现实世界中,一周的天数不能改变。如果语言停止了您的异常,如果只有这一种情况,您需要打破规则……那么您将不得不停止将其声明为常量,即使它在应用程序中仍然是常量,并且只有这一个测试案例可以看到如果它被更改会发生什么。

    全部大写的名称告诉您它是一个常量。这才是最重要的。不是一种强制对代码进行约束的语言,您无论如何都有权更改它。

    这就是Python的哲学。


    我们可以创建一个描述符对象。

    1
    2
    3
    4
    5
    6
    7
    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)如果我们想在实例级别使用常量,那么:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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

    2)如果我们只想在类级别创建常量,我们可以使用一个元类作为常量(描述符对象)的容器;所有下降的类将继承我们的常量(描述符对象),而不会有任何可以修改的风险。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # 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的子类,这个类将继承常量而不修改它们。

    1
    2
    3
    4
    class Bar(Foo): pass

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

    有一种更简单的方法可以使用NamedDuple执行此操作:

    1
    2
    3
    4
    5
    from collections import namedtuple


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

    使用实例

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

    通过这种精确的方法,您可以为常量命名。


    Python dictionaries are mutable, so they don't seem like a good way to declare constants:

    1
    2
    3
    4
    5
    6
    >>> constants = {"foo":1,"bar":2}
    >>> print constants
    {'foo': 1, 'bar': 2}
    >>> constants["bar"] = 3
    >>> print constants
    {'foo': 1, 'bar': 3}

    也许pconst库可以帮助您(github)。

    $ pip install pconst

    1
    2
    3
    from pconst import const
    const.APPLE_PRICE = 100
    const.APPLE_PRICE = 200

    [Out] Constant value of"APPLE_PRICE" is not editable.


    (本段是对这些答案的评论,其中提到了namedtuple,但这段时间太长了,不适合评论,所以,这里就有了。)

    上面提到的命名双重方法绝对是创新的。不过,为了完整起见,在其官方文件的命名双重部分的末尾,它写道:

    enumerated constants can be implemented with named tuples, but it is simpler and more efficient to use a simple class declaration:

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

    换句话说,官方文档更喜欢使用实际的方式,而不是实际实现只读行为。我想它是另一个关于Python禅宗的例子:

    Simple is better than complex.

    practicality beats purity.


    你只需:

    1
    2
    STRING_CONSTANT ="hi"
    NUMBER_CONSTANT = 89

    希望一切都简单多了


    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 (' # ') e.g. :

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

    您可以使用StringVar或IntVar等,您的常量是常量

    1
    2
    3
    4
    5
    6
    val = 'Stackoverflow'
    const_val = StringVar(val)
    const.trace('w', reverse)

    def reverse(*args):
        const_val.set(val)

    在我的例子中,我需要不可变的bytearray来实现一个包含许多我想要确保不变的字面数字的加密库。

    此答案有效,但尝试重新分配bytearray元素不会引发错误。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    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

    常量是不可变的,但常量bytearray分配会自动失败:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    >>> 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')

    一种更强大、更简单、甚至可能更"pythonic"的方法涉及到使用memoryview对象(缓冲区对象在<=python-2.6中)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    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)

    constaray项分配是一个TypeError

    1
    2
    3
    4
    5
    6
    7
    >>> 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
    2
    3
    4
    class RED:
        pass
    class BLUE:
        pass

    我为python const编写了一个util lib:科皮斯特-皮皮支持str,int,float,datetime

    const字段实例将保留其基类型行为。

    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    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

    更多详细信息用法,您可以阅读pypi url:Pypi或Github


    没有完美的方法可以做到这一点。据我所知,大多数程序员只是将标识符大写,所以pi=3.142可以很容易地理解为常量。

    另一方面,如果你想要一个常数,我不确定你会找到它。不管你做什么,总会有一些编辑"常数"的方法,所以它不会真的是一个常数。下面是一个非常简单、肮脏的例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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"))

    这看起来会使PHP样式成为常量。

    实际上,一个人改变价值所需要的就是:

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

    对于您在这里找到的所有其他解决方案来说,这是相同的——即使是那些聪明的解决方案,它们可以创建一个类并重新定义set属性方法——它们总是有一种解决方法的。Python就是这样。

    我的建议是避免所有的麻烦,只是大写您的标识符。它不是一个适当的常数,但同样的,没有什么。


    你可以用collections.namedtupleitertools来实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    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
    One
    >>> print myConstants.Two
    Two
    >>> print myConstants.Three
    Four
    >>> myConstants.One = 'Two'
    Traceback (most recent call last):
      File"<stdin>", line 1, in <module>
    AttributeError: can't set attribute

    可以将常量包装在numpy数组中,将其标记为只写,并始终按索引0调用它。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    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

    当然,这只保护numpy的内容,而不是变量"constant"本身;您仍然可以这样做:

    1
    CONSTANT = 'foo'

    CONSTANT会发生变化,但是这会在脚本中第一次调用CONSTANT[0]时迅速抛出一个类型错误。

    虽然…我想如果你在某个时候把它改成

    1
    CONSTANT = [1,2,3]

    现在你不会再有打字错误了。嗯…

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


    扩展raufio的答案,添加repr返回值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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

    然后,对象的行为会比您预期的稍微好一点,您可以直接访问它,而不是".value"


    在这里的所有答案中,最简单的方法是在python中创建一个常量变量。做一个一维元组。

    1
    myconstant_var = (10,)

    就是这样。现在变量myinstant变量不能更改


    您可以在下一个类的帮助下模拟常量变量。使用示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    # 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)

    当要启动新的常量命名空间时,请调用构造函数。请注意,当martelli的const类不是时,该类受到意外修改序列类型常量的保护。

    资料来源如下。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    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)

    好。。尽管这已经过时了,让我在这里加上我的2美分:—)

    1
    2
    3
    4
    5
    6
    7
    8
    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)

    您可以避免在那里发生任何更新,而不是让ValueError中断。这样做的一个好处是,可以在程序中动态添加常量,但一旦设置了常量,就不能更改。此外,您还可以在设置常量之前添加任何规则或任何内容(例如,键在设置键之前必须是字符串或小写字符串或大写字符串等)。

    但是,我没有看到在Python中设置常量的重要性。没有任何优化可以像在C中那样发生,因此我猜这是不需要的。


    python字典一旦声明就不可更改,可以用作常量。

    [cc lang="python"]my_consts={"TIMEOUT":300,"RETRIES":10,"STATE":"happy