在Python中对相关常量进行分组

8

我正在寻找一种使用Python定义多个相关常量的方法,这些常量可以在多个模块中使用,并且希望它们保存在单个文件中。我想出了几种选项,但它们都有缺点。

方法1-简单的全局常量

# file resources/resource_ids.py

FOO_RESOURCE = 'foo'
BAR_RESOURCE = 'bar'
BAZ_RESOURCE = 'baz'
QUX_RESOURCE = 'qux'

# file runtime/bar_handler.py

from resources.resource_ids import BAR_RESOURCE

# ...

def my_code():
  value = get_resource(BAR_RESOURCE)

这是一种简单且通用的方法,但也有一些缺点:

  • 需要在所有常量名称后添加_RESOURCE以提供上下文。
  • 在IDE中检查常量名称将不会显示其他常量值。

方法2 - 枚举

# file resources/resource_ids.py

from enum import Enum, unique

@unique
class ResourceIds(Enum):
  foo = 'foo'
  bar = 'bar'
  baz = 'baz'
  qux = 'qux'

# file runtime/bar_handler.py

from resources.resource_ids import ResourceIds

# ...

def my_code():
  value = get_resource(ResourceIds.bar.value)

这种方法解决了第一种方法的问题,但这种解决方案的缺点是需要使用.value来获取字符串表示形式(假设我们需要字符串值而不仅是一致的枚举值)。如果未附加.value,可能会导致难以调试的运行时问题。

第三种方法 - 类变量

# file resources/resource_ids.py

class ResourceIds:
  foo = 'foo'
  bar = 'bar'
  baz = 'baz'
  qux = 'qux'

# file runtime/bar_handler.py

from resources.resource_ids import ResourceIds

# ...

def my_code():
  value = get_resource(ResourceIds.bar)

这种方法是我最喜欢的,但可能会被误解 - 类是用来实例化的。虽然使用类的实例而不是类本身不会影响代码正确性,但我想避免这种浪费。

这种方法的另一个缺点是值实际上并不是常量。任何代码客户端都可以潜在地改变它们。

有可能防止一个类被实例化吗?我是否忽略了某些将密切相关的常量分组的惯用方法?

2个回答

10

使用 Enum 并混入 str

@unique
class ResourceIds(str, Enum):
    foo = 'foo'
    bar = 'bar'
    baz = 'baz'
    qux = 'qux'

那么您就不需要与.value进行比较:

>>> ResourceIds.foo == 'foo'
True

您仍然可以获得良好的调试信息:

>>> ResourceIds.foo
<ResourceIds.foo: 'foo'>

>>> list(ResourceIds.foo.__class__)
[
 <ResourceIds.foo: 'foo'>,
 <ResourceIds.bar: 'bar'>,
 <ResourceIds.baz: 'baz'>,
 <ResourceIds.qux: 'qux'>,
]

太好了!它甚至还可以与字典一起使用: d = {ResourceIds.foo: 'foo_value'} print(d['foo']) # 输出 "foo_value" - EvilTosha

1
以下是几种方法,我不太喜欢在Python中使用枚举,因为我认为你不真正需要它们;)。
据我所知,这是大多数包的做法:
# module_name.py
CSV = 'csv'
JSON = 'json'

def save(path, format=CSV):
    # do some thing with format
    ...

# other_module.py
import module_name

module_name.save('my_path', fomat=module_name.CSV)

another way is like this:

# module_name.py
options = {
    'csv': some_csv_processing_function
    'json': some_json_processing_function
}

def save(path, format=options.['csv']:
    # do some thing with format
    ...

# other_module.py
import module_name

module_name.save('my_path', fomat=module_name.options['csv'])

(有点不相关)您还可以将您的字典转换为类:

class DictClass:
    def __init__(self, dict_class):
        self.__dict__ = dict_class

options = DictClass({
    'csv': some_csv_processing_function
    'json': some_json_processing_function
})

现在你可以像访问一个对象一样访问你的字典: options.csv

2
好的,了解了,感谢提供上下文!你认为这些包使用常量而不是枚举是因为它们是在枚举还不存在的时候开发的吗? - EvilTosha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接