[英]Good practice with conditional imports
I have a module for configuration, projectConfig
, to parse a sample sheet for a project: 我有一个配置模块
projectConfig
,用于解析项目的示例表:
class SampleSheetFields():
FIELD_1 = "field1"
FIELD_2 = "field2"
class SampleSheetFieldsOld():
FIELD_1 = "field_1"
FIELD_2 = "field_2"
I had been using the first class in other modules like this: 我一直在使用其他模块中的第一个类,如下所示:
from projectConfig import SampleSheetFields as ssFields
class SomeClass
def __init__(self):
...
check(someContent, ssFields.FIELD_1)
The thing is I had developed my software using the reference to ssFields
quite a lot. 问题是我使用对
ssFields
的引用开发了我的软件。 At some point new specifications said that the software should also use sample sheets with different field names. 在某些时候,新的规范说软件也应该使用具有不同字段名称的样本表。 The quickest way I found to achieve that, without messing too much with the code, was to add the class
SampleSheetFieldsOld
in the projectConfig
and to make a conditional import in my modules: 我发现实现这一目标的最快捷的方法是在
SampleSheetFieldsOld
代码进行过多处理的情况下,在projectConfig
添加类SampleSheetFieldsOld
并在我的模块中进行条件导入:
class SomeClass:
def __init__(self, useOld):
if useOld:
from projectConfig import SampleSheetFieldsOld as ssFields
else:
from projectConfig import SampleSheetFields as ssFields
...
check(someContent, ssFields.FIELD_1)
Note that the mandatory fields which are used have the same name so there is no conflicting or missing field. 请注意,使用的必填字段具有相同的名称,因此没有冲突或缺少字段。 The program works as expected.
该程序按预期工作。
My questions are: 我的问题是:
It's probably not the worst thing, but what I do find kind of problematic is the fact that you're now locked into two configuration options, old and new. 这可能不是最糟糕的事情,但我发现有些问题是你现在被锁定为两个配置选项,无论是新的还是新的。 What if you need to add a third or fourth etc. set someday?
如果你有一天需要添加第三个或第四个等等怎么办? You won't be able to use a simple boolean test anymore.
您将无法再使用简单的布尔测试。
Besides, it looks like your configuration options are all just simple string values, accessible via string keys. 此外,您的配置选项看起来都只是简单的字符串值,可通过字符串键访问。 You don't need a class for that.
你不需要一个班级。
My suggestion is to forget about doing your configuration with the source code and use a configuration file . 我的建议是忘记使用源代码进行配置并使用配置文件 。 In your
projectConfig
you can have a dict
which you initialize from a file, whose path/name can be provided on the command line or in whatever way is convenient. 在您的
projectConfig
您可以拥有一个从文件初始化的dict
,其路径/名称可以在命令行上提供,也可以以任何方便的方式提供。 So projectConfig.py
might go something like this: 所以
projectConfig.py
可能会是这样的:
config_options = {}
def load_configuration(filename):
with open(filename) as f:
for line in f:
# get key and value
config_options[key] = value
Then everywhere you need to get a field name, just access projectConfig.config_options['field_key']
, eg 然后你需要获得一个字段名称,只需访问
projectConfig.config_options['field_key']
,例如
from projectConfig import config_options
class SomeClass
def __init__(self):
...
check(someContent, config_options['FIELD_1'])
Or use dict.get(key, default)
if there is a reasonable default value. 如果有合理的默认值
dict.get(key, default)
使用dict.get(key, default)
。 This way, each time you need to switch to a different set of field names, you just create a new configuration file, and you don't have to touch the code. 这样,每次需要切换到一组不同的字段名称时,只需创建一个新的配置文件,而不必触摸代码。
Python's standard library includes a configparser
module which can handle the loading for you. Python的标准库包含一个
configparser
模块 ,可以为您处理加载。
If you only need the class attributes, you could create a class factory, using type
to create new classes, like: 如果只需要类属性,则可以创建类工厂,使用
type
创建新类,如:
FIELDS = dict(
new=dict(FIELD_1="field1", FIELD_2="field2"),
old=dict(FIELD_1="field_1", FIELD_2="field_2"),
}
def sample_sheet_field_factory(field_spec='new'):
return type("SampleSheetFields", (object,), FIELDS[field_spec])
This can easily be extended to further sets of field specifications, and doesn't require a conditional import: 这可以很容易地扩展到更多的字段规范集,并且不需要条件导入:
from wherever import sample_sheet_field_factory
class SomeClass(object):
def __init__(self, use_old):
ss_fields = sample_sheet_field_factory("old" if use_old else "new")
check(some_content, ss_fields.FIELD_1)
You could also use a namedtuple
, rather than a class, which would be a little more lightweight. 你也可以使用一个
namedtuple
而不是一个类,它会更轻一些。 Note edits for compliance with the style guide . 注意编辑符合样式指南 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.