如何在Python中声明常量?
在Java中,我们做:
public static final String CONST_NAME = "Name";
如何在Python中声明常量?
在Java中,我们做:
public static final String CONST_NAME = "Name";
当前回答
在Python中创建常量的更好方法是从 优秀的attrs库,这很有帮助 Python程序员创建类时不使用样板文件。的 Short-con package也有同样的功能 常量,提供一个方便的包装器 attr.make_class。[声明:我是short-con的作者。]
值可以通过dict或kwargs显式声明 例子也有同样的作用。常量()函数支持的所有特性 库和cons()是简单使用kwarg的辅助程序。
from short_con import constants, cons
Pieces = constants('Pieces', dict(king = 0, queen = 9, rook = 5, bishop = 3, knight = 3, pawn = 1))
Pieces = cons('Pieces', king = 0, queen = 9, rook = 5, bishop = 3, knight = 3, pawn = 1)
的值相同(或可以从其导出)的情况 属性名,使用更加紧凑。只提供名称作为 空格分隔的字符串、列表或元组。
NAMES = 'KING QUEEN ROOK BISHOP KNIGHT PAWN'
xs = NAMES.split()
Pieces = constants('Pieces', NAMES) # All of these do the same thing.
Pieces = constants('Pieces', xs)
Pieces = constants('Pieces', tuple(xs))
基于名称的用法支持一些风格约定:大写或 小写的属性名,以及枚举样式的值。
方法创建的常量不同,底层值可以直接访问 内置枚举库:
Pieces.QUEEN # short-con usage
Pieces.QUEEN.value # enum library usage
对象直接可迭代,可转换为其他集合:
for name, value in Pieces:
print(name, value)
d = dict(Pieces)
tups = list(Pieces)
其他回答
除了上面的两个答案(只使用大写的变量名,或者使用属性使值为只读),我想提到的是,可以使用元类来实现命名常量。我在GitHub提供了一个使用元类的非常简单的解决方案,如果你想让值的类型/名称更有信息,这可能会很有帮助:
>>> 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,但仍然非常容易使用和方便。(该模块有更多的特性,包括常量是只读的,请参阅它的README。)
在各种存储库中也有类似的解决方案,但据我所知,它们要么缺乏我对常量所期望的基本特性之一(比如是常量,或者是任意类型),要么添加了一些深奥的特性,使它们不那么普遍适用。但是YMMV,我很感激你的反馈。: -)
在其他语言中没有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选择这些名称的事实,并使用应用于该作用域的所有本地定义的**(双星号)创建一个关键字字典,将参数传递给属性函数
嗯. .尽管这是过时的,让我在这里补充我的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中那样发生,因此它是不需要的,我猜。
我正在尝试用不同的方法在Python中创建一个真正的常量,也许我找到了漂亮的解决方案。
例子:
为常量创建容器
>>> DAYS = Constants(
... MON=0,
... TUE=1,
... WED=2,
... THU=3,
... FRI=4,
... SAT=5,
... SUN=6
... )
从容器中获取价值
>>> DAYS.MON
0
>>> DAYS['MON']
0
用纯python数据结构表示
>>> list(DAYS)
['WED', 'SUN', 'FRI', 'THU', 'MON', 'TUE', 'SAT']
>>> dict(DAYS)
{'WED': 2, 'SUN': 6, 'FRI': 4, 'THU': 3, 'MON': 0, 'TUE': 1, 'SAT': 5}
所有常数都是不可变的
>>> DAYS.MON = 7
...
AttributeError: Immutable attribute
>>> del DAYS.MON
...
AttributeError: Immutable attribute
仅对常量自动补全
>>> dir(DAYS)
['FRI', 'MON', 'SAT', 'SUN', 'THU', 'TUE', 'WED']
像list.sort那样排序
>>> DAYS.sort(key=lambda (k, v): v, reverse=True)
>>> list(DAYS)
['SUN', 'SAT', 'FRI', 'THU', 'WED', 'TUE', 'MON']
与python2和python3的兼容性
常量的简单容器
from collections import OrderedDict
from copy import deepcopy
class Constants(object):
"""Container of constant"""
__slots__ = ('__dict__')
def __init__(self, **kwargs):
if list(filter(lambda x: not x.isupper(), kwargs)):
raise AttributeError('Constant name should be uppercase.')
super(Constants, self).__setattr__(
'__dict__',
OrderedDict(map(lambda x: (x[0], deepcopy(x[1])), kwargs.items()))
)
def sort(self, key=None, reverse=False):
super(Constants, self).__setattr__(
'__dict__',
OrderedDict(sorted(self.__dict__.items(), key=key, reverse=reverse))
)
def __getitem__(self, name):
return self.__dict__[name]
def __len__(self):
return len(self.__dict__)
def __iter__(self):
for name in self.__dict__:
yield name
def keys(self):
return list(self)
def __str__(self):
return str(list(self))
def __repr__(self):
return '<%s: %s>' % (self.__class__.__name__, str(self.__dict__))
def __dir__(self):
return list(self)
def __setattr__(self, name, value):
raise AttributeError("Immutable attribute")
def __delattr__(*_):
raise AttributeError("Immutable attribute")
在Python中创建常量的更好方法是从 优秀的attrs库,这很有帮助 Python程序员创建类时不使用样板文件。的 Short-con package也有同样的功能 常量,提供一个方便的包装器 attr.make_class。[声明:我是short-con的作者。]
值可以通过dict或kwargs显式声明 例子也有同样的作用。常量()函数支持的所有特性 库和cons()是简单使用kwarg的辅助程序。
from short_con import constants, cons
Pieces = constants('Pieces', dict(king = 0, queen = 9, rook = 5, bishop = 3, knight = 3, pawn = 1))
Pieces = cons('Pieces', king = 0, queen = 9, rook = 5, bishop = 3, knight = 3, pawn = 1)
的值相同(或可以从其导出)的情况 属性名,使用更加紧凑。只提供名称作为 空格分隔的字符串、列表或元组。
NAMES = 'KING QUEEN ROOK BISHOP KNIGHT PAWN'
xs = NAMES.split()
Pieces = constants('Pieces', NAMES) # All of these do the same thing.
Pieces = constants('Pieces', xs)
Pieces = constants('Pieces', tuple(xs))
基于名称的用法支持一些风格约定:大写或 小写的属性名,以及枚举样式的值。
方法创建的常量不同,底层值可以直接访问 内置枚举库:
Pieces.QUEEN # short-con usage
Pieces.QUEEN.value # enum library usage
对象直接可迭代,可转换为其他集合:
for name, value in Pieces:
print(name, value)
d = dict(Pieces)
tups = list(Pieces)