python - 通过巧妙的导入管理 Python 模块依赖关系

标签 python

我正在编写一个 python 模块,该模块抽象了针对不同 CPU 架构的三种不同硬件调试工具的使用。

为了说明我的问题,我们假设我正在编写一个配置数据库,该数据库抽象使用 XML、YAML 和 JSON 文件来存储内容:

import xml.etree.ElementTree as ET
import json
import yaml

class abstract_data:
    def __init__(self, filename):
        '''
        Loads a file regardless of the type

        Args:
            filename (str): The file that has the data
        '''
        if filename.endswith('.xml'):
            self.data = ET.parse(filename)
        else:
            with open(filename) as f:
                if filename.endswith('.json'):
                    self.data = json.load(f)
                elif filename.endswith('.yaml'):
                    self.data = yaml.load(f, Loader=yaml.FullLoader)

    def do_something(self):
        print(self.data)

def main():
    d = abstract_data("test.yaml")
    d.do_something()

if __name__ == "__main__":
    # execute only if run as a script
    main()

但是,我知道 99% 的用户只会使用 JSON 文件,并且设置其他两个库并不是很容易。

但是,如果我只是像 PEP-8 状态那样将导入放在源代码之上,将为所有用户创建这三个库的依赖关系。我想避免这种情况。

我的(可能是糟糕的解决方案)是使用条件导入,如下所示:

class abstract_data:
    def __init__(self, filename):
        '''
        Loads a file regardless of the type

        Args:
            filename (str): The file that has the data
        '''
        if filename.endswith('.xml'):
            import xml.etree.ElementTree as ET
            self.data = ET.parse(filename)
        else:
            with open(filename) as f:
                if filename.endswith('.json'):
                    self.data = json.load(f)
                elif filename.endswith('.yaml'):
                    import yaml
                    self.data = yaml.load(f, Loader=yaml.FullLoader)

虽然这似乎适用于简单的模块,但这是否是处理此问题的最佳方法?有副作用吗?

请注意,我使用 XML、JSON 和 YAML 作为三种不同导入的说明性案例。

非常感谢!

最佳答案

如果您希望保持类的实现不变,常见的模式是在模块顶部根据导入成功设置一个标志:

try:
    import yaml
except ImportError:
    HAS_YAML = False
else:
    HAS_YAML = True

class UnsupportedFiletypeError(Exception):
    pass

特别是对于较大的项目,将其放入单个模块中,尝试仅导入一次,然后在其他地方使用该事实可能会很有用。例如,将以下内容放入 _deps.py 中并使用 from ._deps import HAS_YAML

然后:

# ...
elif filename.endswith('.yaml'):
    if not HAS_YAML:
        raise UnsupportedFiletypeError("You must install PyYAML for YAML file support")

其次,如果这是一个可安装的 Python 包,请考虑使用 extras_require .

这会让用户执行以下操作:

pip install pkgname[yaml]

如果指定了 pkgname[yaml] 而不仅仅是 pkgname,则 PyYAML 将作为依赖项安装。

关于python - 通过巧妙的导入管理 Python 模块依赖关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62517711/

相关文章:

python - 如何在 Popen python 中使用 fifo 命名管道作为标准输入

python - 在 Mac OS X 10.6 上为 Apache 2.2.21、Python 2.5.4 安装 mod_python

Python/Pandas - 将 3 个数据集组合成一个柱形图

python - 如何在 CPLEX Python 中实现逻辑 OR 约束

Python C API - 从嵌入式 python 调用 C 函数(回调)

python - 如何找到图像中所有矩形瓷砖?

python - 用掩码生成所有可能的数字

python - 在 django 中更改 slug 使用 slugify

python 集合与元组查找。是元组 O(1) 中的查找?

python - 如何根据 SciPy 中的给定数据设置 numpy.arange 的值?