如何方便地定义命名整数常数的列表



我想定义常数,例如A = 10; B = 20,具有这些属性:

  1. "正常"访问:例如A.value + B.value == 30(甚至A + B == 30(
  2. 允许重复值:例如A = 10; B = 10
  3. 每个变量的关联字符串:例如A.name == "A"
  4. 清单:例如[v.name for v in CONSTANTS]
  5. IDE支持:自动完整名称,重新输入等等
  6. 添加新常数需要一个更改
  7. 可进口:例如from config import CONSTANTS

最后,属性#6是问题所在。像

A = 10
B = 20
A_NAME = "A"
B_NAME = "B"
CONSTANTS = { A_NAME: A, B_NAME: B }

基本上是解决方案。但是我想避免使用此详细代码(如果可能的话(。


此尝试非常接近:

import enum
class CONSTANTS(enum.IntEnum):
    A = 10
    B = 20
assert CONSTANTS.A + CONSTANTS.B == 30
assert CONSTANTS.A.name == "A"
assert CONSTANTS.__members__.keys() == ["A", "B"]
assert CONSTANTS.__members__.values() == [10, 20]

,但是当两个常数具有相同的值(属性#2(时失败。一个人还可以用 value的构造函数来定义Enum的子类。但是同样,即使名称有所不同,A = 10; B = 10也会映射到同一实例。现在,人们还可以在构造函数中添加名称(或任何其他未使用但独特的参数(,以使此问题消失。但是我认为这种方法不洁。例如,A = ("A", 10); B = ("B", 10); def __init__(self, _, value): ...

您可以通过使用 globals()将dict内容复制到全局变量的情况下使常数少详细。

CONSTANTS = {"A": 10, "B": 20}
globals().update(CONSTANTS)
print(B)  # prints 20

您是否考虑过使用名为Tuple Collection?

from collections import namedtuple
IntConst = namedtuple('IntConst', ['name', 'value'])
A = IntConst('A',10)
B = IntConst('B',20)

他们按字段符合您的"正常访问" ..

A.value + B.value

当多个IntConst具有相同的值时,他们不会抱怨...

A = IntConst('A',10)
B = IntConst('B',10)

他们将提供关联的字符串...

A.name

他们将允许列表...

CONSTANTS = list()
CONSTANTS.extend([A,B])
[v.name for v in CONSTANTS]

您的IDE可能已经支持namedtuple。添加更多常数只需您创建IntConst namedtuple的实例即可。至于导入,您只需在命名空间中创建一个IntConst值的列表,它们将成为import语句的有效目标。

他们唯一不给您要求的东西是能够从中输入整数值。相反,您将获得一个包含两个IntConst实例的元组。

>>> A+B
('A', 10, 'B', 10)

免责声明:访问隐藏属性是不建议的,因此不应被视为'干净'解决方案!

标准枚举模块可以进行调整提供所需的行为。

import enum
class Const1(enum.Enum):
    A = 42
    B = 42
    def __init__(self, size):
        self._value_ = (self.name, size)
        self.size = size
class Const2(enum.IntEnum):
    A = 42
    B = 42
    def __init__(self, size):
        enum.IntEnum.__init__(self)
        self._value_ = (self.name, size)

用成员名称填充_value_属性,呈现出别名查找机制无法找到具有相同值的其他成员。唯一的缺点是,生产成员的value属性均参考其内部_value_属性。实际上,value定义为DynamicClassAttribute。因此,没有进一步的修改我们面对:Const1.A.value == ('A', 42)

如果需要,可以使用属性来覆盖此行为。

@property
def value(self):
    return self._value_[1]

最新更新