如何在Python中声明常量?
在Java中,我们做:
public static final String CONST_NAME = "Name";
如何在Python中声明常量?
在Java中,我们做:
public static final String CONST_NAME = "Name";
当前回答
嗯. .尽管这是过时的,让我在这里补充我的2分:-)
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。这样做的一个好处是,您可以在程序中动态地添加常数,但一旦设置了常数就不能更改。你也可以在设置常量之前添加任何规则(比如key必须是字符串或小写字符串或大写字符串等)
然而,我不认为在Python中设置常量有任何重要性。没有优化可以像在C中那样发生,因此它是不需要的,我猜。
其他回答
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
Enum和str的混合让你不必重新实现setattr(通过Enum),也不必与其他str对象进行比较(通过str)。
这可能会使http://code.activestate.com/recipes/65207-constants-in-python/?in=user-97991完全弃用。
在其他语言中没有const关键字,但是可以创建一个具有“getter函数”来读取数据,但没有“setter函数”来重写数据的Property。这从本质上保护标识符不被更改。
下面是一个使用class属性的替代实现:
请注意,对于想了解常量的读者来说,代码远非简单。见下面的解释。
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(hex(CONST.FOO)) # -> '0xbaadfaceL'
CONST.FOO = 0
##Traceback (most recent call last):
## File "example1.py", line 22, in <module>
## CONST.FOO = 0
## File "example1.py", line 5, in fset
## raise TypeError
##TypeError
代码的解释:
定义一个接受表达式的函数常量,并使用它来构造一个“getter”——一个仅返回表达式值的函数。 setter函数引发TypeError,因此它是只读的 使用我们刚刚创建的常量函数作为装饰来快速定义只读属性。
用另一种更传统的方式:
(代码相当棘手,下面有更多解释)
class _Const(object):
def FOO():
def fset(self, value):
raise TypeError
def fget(self):
return 0xBAADFACE
return property(**locals())
FOO = FOO() # Define property.
CONST = _Const()
print(hex(CONST.FOO)) # -> '0xbaadfaceL'
CONST.FOO = 0
##Traceback (most recent call last):
## File "example2.py", line 16, in <module>
## CONST.FOO = 0
## File "example2.py", line 6, in fset
## raise TypeError
##TypeError
要定义标识符FOO,首先定义两个函数(fset, fget -名称由我选择)。 然后使用内置的属性函数构造一个可以“set”或“get”的对象。 注意属性函数的前两个参数名为fset和fget。 利用我们为自己的getter和setter选择这些名称的事实,并使用应用于该作用域的所有本地定义的**(双星号)创建一个关键字字典,将参数传递给属性函数
所有给出的答案基本上有两种类型:
创建一些你可以实现的对象 创建一旦定义就不能更改的属性。 使用约定(比如常量全部大写,或者对于Python 3.8,使用最后一个限定符来表示一个或多个名称是常量。
他们可以总结为“你不能用Python做你想做的事情”。
然而,实际上有一种方法可以创建具有真正常量的模块。这样做的代码相当复杂,我将只给出需要做什么,因为它在开源许可下已经可用。
使用导入钩子来创建自定义模块。这里可以找到我为此使用的通用代码。 创建一个特殊的字典,允许只添加一次符合您所选模式的项(例如,名称全部大写),并防止此类名称的值被更改。为此,你需要定义自己的方法,如__setitem__, __delitem__等。这种字典的代码(比如在这个文件中找到的,超过250行)大约有100行长。 普通Python模块的dict不能被修改。因此,在创建模块时,您需要首先执行特殊字典中的代码,然后使用其内容更新模块的字典。 为了防止从模块外部修改常量的值(即monkeypatching),您可以用重新定义的__setattr__和__delattr__方法将模块的__class__替换为自定义的__class__。
关于这个示例的文档可以在这里找到。它可能应该更新,以反映这个问题的答案的数量。
Python字典是可变的,所以它们似乎不是声明常量的好方法:
>>> constants = {"foo":1, "bar":2}
>>> print constants
{'foo': 1, 'bar': 2}
>>> constants["bar"] = 3
>>> print constants
{'foo': 1, 'bar': 3}
您可以将一个常量包装在numpy数组中,将其标记为仅写,并始终通过下标0调用它。
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”本身;你仍然可以:
CONSTANT = 'foo'
和CONSTANT会改变,然而,这将很快抛出TypeError第一次在脚本中调用CONSTANT[0]。
尽管……我想如果你在某个时候把它改成
CONSTANT = [1,2,3]
现在你不会再得到TypeError了。嗯……
https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.setflags.html