条件导入的良好做法

时间:2015-11-18 12:05:42

标签: python import maintainability

我有一个配置模块projectConfig,用于解析项目的样本表:

class SampleSheetFields():
    FIELD_1 = "field1"
    FIELD_2 = "field2"


class SampleSheetFieldsOld():
    FIELD_1 = "field_1"
    FIELD_2 = "field_2"

我一直在使用其他模块中的第一个类:

from projectConfig import SampleSheetFields as ssFields

class SomeClass

    def __init__(self):
        ...
        check(someContent, ssFields.FIELD_1)

事情是我使用ssFields的引用开发了我的软件。在某些时候,新的规范说软件也应该使用具有不同字段名称的样本表。我发现实现这一目标的最快方式是在SampleSheetFieldsOld中添加类projectConfig并在我的模块中进行条件导入:

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)

请注意,使用的必填字段具有相同的名称,因此没有冲突或缺少字段。该计划按预期运作。

我的问题是:

  1. 这种做法有多糟糕,如果不好的话;和
  2. 我如何规避它以制作更好,更可持续的代码?

2 个答案:

答案 0 :(得分:3)

这可能不是最糟糕的事情,但我发现的问题是你现在已经锁定了两个配置选项,无论是新旧配置。如果你有一天需要添加第三个或第四个等等怎么办?你再也不能使用简单的布尔测试了。

此外,您的配置选项看起来都只是简单的字符串值,可通过字符串键访问。你不需要上课。

我的建议是忘记使用源代码进行配置并使用配置文件。在projectConfig中,您可以从文件初始化dict,其路径/名称可以在命令行上提供,也可以以任何方便的方式提供。所以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

然后,无论您需要获取字段名称,只需访问projectConfig.config_options['field_key'],例如

from projectConfig import config_options

class SomeClass

    def __init__(self):
        ...
        check(someContent, config_options['FIELD_1'])

如果有合理的默认值,请使用dict.get(key, default)。这样,每次需要切换到一组不同的字段名称时,您只需创建一个新的配置文件,而不必触摸代码。

Python的标准库包含configparser module,可以为您处理加载。

答案 1 :(得分:0)

如果您只需要类属性,则可以使用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])

这可以很容易地扩展到更多的字段规范集,并且不需要条件导入:

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)

你也可以使用namedtuple,而不是一个类,它会更轻一些。请注意编辑符合the style guide