我正在编写一个 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/