在 Python 中分组相关常量
Group related constants in Python
我正在寻找一种 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 - class 变量
# 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)
这种方法是我最喜欢的,但它可能会被误解 - classes 是用来实例化的。虽然代码正确性不会因使用 class 的实例而不是 class 本身而受到影响,但我想避免这种浪费。
这种方法的另一个缺点是值实际上不是常量。任何代码客户端都可能更改它们。
是否可以阻止 class 被实例化?我是否缺少一些惯用的方法来对密切相关的常量进行分组?
使用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'>,
]
有几种方法可以做到这一点,我不太喜欢在 python 中使用枚举,因为在我看来你 真的 不需要它们 ;)
大多数包都是这样做的 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'])
(有点无关)你也可以让你的命令 类:
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
我正在寻找一种 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 - class 变量
# 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)
这种方法是我最喜欢的,但它可能会被误解 - classes 是用来实例化的。虽然代码正确性不会因使用 class 的实例而不是 class 本身而受到影响,但我想避免这种浪费。
这种方法的另一个缺点是值实际上不是常量。任何代码客户端都可能更改它们。
是否可以阻止 class 被实例化?我是否缺少一些惯用的方法来对密切相关的常量进行分组?
使用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'>,
]
有几种方法可以做到这一点,我不太喜欢在 python 中使用枚举,因为在我看来你 真的 不需要它们 ;)
大多数包都是这样做的 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'])
(有点无关)你也可以让你的命令 类:
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