Python条件导入的设计

Jul*_*ago 4 python design-patterns module

我是 Python 条件导入新手,正在考虑两种模块设计方法。我很乐意了解为什么我可能想要选择其中一种(或者是否存在更好的替代方案)。

问题

我有一个程序需要在不同条件下调用结构相同但不同的模块。这些模块都具有相同的功能、输入、输出等,唯一的区别在于它们在其功能内执行的操作。例如,

# module_A.py
def get_the_thing(input):
    # do the thing specific to module A
    return thing

# module_B.py
def get_the_thing(input):
    # do the thing specific to module B
    return thing
Run Code Online (Sandbox Code Playgroud)

选项1

根据输入值,我将根据此答案有条件地导入适当的模块。

if val == 'A':
    import module_A
if val == 'B':
    import module_B
Run Code Online (Sandbox Code Playgroud)

选项2

我使用输入变量将模块名称生成为字符串,然后使用此方法根据该字符串从正确的模块调用该函数。我相信这需要我首先导入所有模块。

import module_A
import module_B

in_var = get_input() # Say my input variable is 'A', meaning use Module A
module_nm = 'module_' + in_var
function_nm = 'get_the_thing'

getattr(globals()[module_nm], function_nm)(my_args)
Run Code Online (Sandbox Code Playgroud)

这个想法是,这将通过在运行时生成模块和函数名称来调用 module_A.get_the_thing() 。这是一个仅针对一个函数调用的无聊示例,但在我的实际情况中,我将使用一系列函数,只是想让事情变得简单。

对于这两种设计是否更好,或者是否存在比这两种更好的东西,有什么想法吗? 将不胜感激任何原因。当然,A 更简洁,可能更直观,但不确定这是否一定等同于良好的设计或性能差异。

Car*_*ate 5

我会选择选项 1。它明显更简洁,而且您不需要摆弄字符串来进行查找。处理字符串至少会使重构变得复杂。如果您更改了任何涉及的名称,则必须记住也更新字符串;特别是因为即使是智能 IDE 也无法帮助您进行典型的shiftF6命名。难以维护这样的代码的地方越少越好。

不过我会对 1 做一个小改动。按照您现在的方式,每次使用该模块仍然需要使用限定名称,例如module_A.do_thing(). 这意味着每当您想要调用一个函数时,您都需要首先弄清楚首先导入的是哪个函数,这会导致代码更加混乱。我会用一个通用名称导入它们:

if val == 'A':
    import module_A as my_module

if val == 'B':
    import module_B as my_module

. . .

my_module.do_thing()  # The exact function called will depend on which module was imported as my_module
Run Code Online (Sandbox Code Playgroud)

您还可以按照评论中的建议使用通配符导入来避免需要使用模块名称:

if val == 'A':
    from module_A import *

if val == 'B':
    from module_B import *

. . .

do_thing()
Run Code Online (Sandbox Code Playgroud)

但这是PEP8不鼓励的:

from <module> import *应避免通配符导入 ( ),因为它们使命名空间中存在哪些名称变得不清楚,从而使读者和许多自动化工具感到困惑。

它还会污染您要导入的名称空间,从而更容易意外地隐藏导入文件中的名称。