我正在开发实现科学模型的 python 包,我想知道处理可选功能的最佳方法是什么。 这是我想要的行为: 如果无法导入某些可选依赖项(例如,在无头机器上绘制模块),我想在我的类中禁用使用这些模块的功能,警告用户如果他尝试使用它们以及所有这些,而不会破坏执行。 所以下面的脚本在任何情况下都可以工作:
mymodel.dostuff()
mymodel.plot() <= only plots if possible, else display log an error
mymodel.domorestuff() <= get executed regardless of the result of the previous statement
到目前为止,我看到的选项如下:
-
检查
__init __.py
可用模块并保留以下列表 它们(但如何在包的其余部分正确使用它?) -
对于依赖可选依赖项的每个函数都有一个
try import ... except ...
声明 - 将依赖于特定模块的函数放在单独的文件中
这些选项应该有效,但它们似乎都相当老套且难以维护。如果我们想完全放弃依赖怎么办?或强制执行?
在 Python 中处理可选依赖关系的最佳实践是尽可能利用
try
/
except
块,结合清晰的文档和在需要时使用像
warnings
或
logging
模块的警告。以下是如何构建代码的方法:
-
requirements.txt
: 在requirements.txt
文件中分离的核心依赖关系和可选依赖关系。
``` # 核心依赖关系 numpy scipy
# 可选依赖关系 matplotlib seaborn ```
-
setup.py
: 使用setup.py
文件中的extras_require
参数来指定可选依赖关系。这使用户可以使用pip
安装这些依赖关系:
```python from setuptools import setup
setup( ... install_requires=['numpy', 'scipy'], extras_require={ 'plotting': ['matplotlib', 'seaborn'], }, ... ) ```
用户现在可以通过运行以下命令来安装绘图依赖关系:
bash
pip install yourpackage[plotting]
-
优雅地处理
ImportError
: 在的模块或类中,使用try
/except
块导入可选依赖关系并在无法导入时提供适当的回退行为或警告。
```python import logging
# 配置日志记录(可以自定义) logging.basicConfig(level=logging.WARNING)
try: import matplotlib.pyplot as plt _PLOTTING_AVAILABLE = True except ImportError: _PLOTTING_AVAILABLE = False logging.warning("未安装 matplotlib。将禁用绘图功能。")
class YourModel: # ... 你的类定义 ...
def plot(self, *args, **kwargs):
if _PLOTTING_AVAILABLE:
# 使用 matplotlib 进行绘图
plt.plot(*args, **kwargs)
plt.show()
else:
logging.warning("绘图功能不可用。请安装 matplotlib。")
def dostuff(self):
# 与绘图无关的代码
pass
def domorestuff(self):
# 与绘图无关的代码
pass
```
说明:
-
清晰的警告:
使用
logging
模块或warnings
模块向用户提供信息性消息,说明为什么某个功能不可用并说明如何启用它(例如,安装matplotlib
)。 -
集中式导入:
为了更好的可维护性,在一个地方处理可选的导入(例如,在模块的顶部或类的
__init__
方法中)。 -
私有标志:
使用私有标志(例如,
_PLOTTING_AVAILABLE
)来指示依赖关系是否可用,从而避免在每次使用时检查。 - 备用行为: 为依赖可选依赖关系的功能提供有意义的备用行为。这可能包括跳过该操作、返回默认值或执行替代计算。
优点:
- 干净且易懂的代码。
- 易于维护和扩展,可以使用其他可选依赖关系。
- 为用户提供有关丢失依赖关系的信息性消息。
- 允许在没有可选依赖关系的情况下正常降级。
这种方法遵循了 Python 的“请求宽恕比请求许可更容易”的理念,并提供了用户友好且健壮的方式来处理可选依赖关系。
标签:python,python-3.x From: 27361427