如何在Python中声明常量?
在Java中,我们做:
public static final String CONST_NAME = "Name";
如何在Python中声明常量?
在Java中,我们做:
public static final String CONST_NAME = "Name";
当前回答
我最近发现了一个非常简洁的更新,它会自动引发有意义的错误消息,并阻止通过__dict__访问:
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__访问路由。当然,整个对象仍然可以重新定义。
编辑-原始解决方案
我可能忽略了一个技巧,但这似乎对我有用:
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
创建实例允许神奇的__setattr__方法介入并拦截设置FOO变量的尝试。如果您愿意,可以在这里抛出异常。通过类名实例化实例可以防止直接通过类进行访问。
对于一个值来说,这非常麻烦,但是您可以将许多值附加到CONST对象上。有一个上层的类,类名似乎也有点难看,但我认为它总体上是相当简洁的。
其他回答
也许pconst库会帮助你(github)。
$ PIP安装pconst
from pconst import const
const.APPLE_PRICE = 100
const.APPLE_PRICE = 200
“APPLE_PRICE”的常量值不可编辑。
扩展Raufio的答案,添加__repr__来返回值。
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字典是可变的,所以它们似乎不是声明常量的好方法:
>>> constants = {"foo":1, "bar":2}
>>> print constants
{'foo': 1, 'bar': 2}
>>> constants["bar"] = 3
>>> print constants
{'foo': 1, 'bar': 3}
Python没有常量。
也许最简单的替代方法是为它定义一个函数:
def MY_CONSTANT():
return 42
MY_CONSTANT()现在拥有常量的所有功能(加上一些讨厌的大括号)。
在我的例子中,我需要不可变字节数组来实现包含许多文字数字的加密库,我想确保这些数字是常量。
这个答案是有效的,但是尝试重赋bytearray元素不会引发错误。
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赋值默默失败:
>>> 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')
一种更强大、更简单,甚至可能更“python化”的方法涉及使用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'))
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)
ConstArray项赋值是一个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