3

我正在寻找一种pythonic方法来在单个文件中定义多个相关常量以在多个模块中使用。我想出了多种选择,但它们都有缺点。

方法 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可能会导致在运行时难以调试问题。

方法 3 - 类变量

# 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)

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

这种方法的另一个缺点是这些值实际上并不是恒定的。任何代码客户端都可能更改它们。

是否可以防止类被实例化?我是否错过了一些将密切相关的常量分组的惯用方式?

4

2 回答 2

5

使用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'>,
]
于 2020-05-05T22:53:09.540 回答
1

有几种方法可以做到这一点,我真的不喜欢在 python 中使用枚举,因为你真的不需要它们 IMO ;)

这就是大多数软件包的方式AFAIK:

# 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)

另一种方式是这样的:

# 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'])

(有点不相关)你也可以让你的 dicts 类:

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

于 2020-05-05T23:24:14.017 回答