问题
在python中遇到ImportError,是直接报错让用户安装,还是用import chain?
描述
我在尝试使用 lxml 包在 python 中解析 xml 文件时遇到了这个问题。
在其官方文档中,它说:
If your code only uses the ElementTree API and does not rely on any functionality that is specific to lxml.etree, you can also use (any part of) the following import chain as a fall-back to the original ElementTree:
try:
from lxml import etree
print("running with lxml.etree")
except ImportError:
try:
import xml.etree.cElementTree as etree
print("running with cElementTree on Python 2.5+")
except ImportError:
...
在我看来,导入一个替换是个坏主意,因为:
如果您可以导入另一个库作为替代,它可能没有 lxml 的所有方法,那么您的所有脚本只能基于所有包中的那些可用方法。
那么引入最强大的包(例如这里的lxml)就没有意义了,我们可以直接引入功能最少的一个,并节省大量代码。或者,如果我们以后想使用其他方法,那么我们应该直接引发 ImportError。
但是,正如 Error handling when importing modules 中的回答,我发现这种方法似乎在 python 编程中经常使用:
it's useful to define multi-level functionality based on what library has been imported in runtime.
但在我看来,多级功能只能通过不断检查是否导入了一个库来实现,这使得整个代码变得复杂和丑陋。
因此,我只是想知道为什么人们有时会使用这样的结构,而不是直接引发错误?
最佳答案
首先回答你的最后一个问题:
When encounter ImportError in python, should I directly raise the error and ask the user to install it, or should I use import chain?
您可以出于多种原因处理 ImportError
:
- 如果你的模块直接依赖于一个模块,让错误发生。如果依赖项的安装非常重要,一些库会使用有用的错误消息重新引发错误。
- 如果您的模块试图用速度较慢的库替换具有相同 API 的速度较快的库,则没有理由在屏幕上打印任何内容。
- 如果您的模块需要某个库存在,但您能找到的只有一个明显较慢的库,警告可能有用,让开发人员知道您的模块仍可运行,但不会达到应有的速度.
现在回答你的其他问题:
Then it make less sense to import the most powerful package (e.g. lxml here), we could directly import the least functional one, and save a lot codes.
在 lxml.etree
、ElementTree
和 cElementTree
的特定情况下,这三个都实现了相同的 API。他们是彼此的替代品。 ElementTree
是纯 Python 的,将始终有效,但 cElementTree
通常存在并且速度更快。 lxml.etree
更快,但它是一个外部模块。
可以这样想:
try:
import super_fast_widget as widget
except ImportError:
try:
import fast_widget as widget
except ImportError:
import slow_widget as widget
从您的代码的角度来看,widget
将始终以相同的方式工作,无论实际上最终导入了哪个库,因此最好尝试导入最快的实现,如果性能不佳,则退回到较慢的实现你关心的事情。
您是正确的,如果您允许后备库,您将无法充分利用 所有 lxml
的功能。这就是为什么使用 lxml.etree
而不仅仅是 lxml
的原因。它有意模仿其他两个库的 API。
这是 Django 代码库中的一个类似示例:
# Use the C (faster) implementation if possible
try:
from yaml import CSafeLoader as SafeLoader
from yaml import CSafeDumper as SafeDumper
except ImportError:
from yaml import SafeLoader, SafeDumper
Python 在内部为许多内置模块执行此操作。有一个较慢的纯 Python 版本用作较快的 C 版本的后备。
However, as answered in Error handling when importing modules , I find this approach seems to be used frequently in python programming:
您的lxml.etree
示例将较慢的库替换为较快的库。链接的示例代码为一堆库定义了一个通用的跨平台接口(interface) (getpass
),这些库都执行相同的操作(提示您输入密码)。作者处理了 ImportError
,因为根据您的操作系统,这些单独的模块可能不存在。
您可以将一些 try
block 替换为 if platform.system() == 'Windows'
和类似代码,但即使在单个操作系统中也可能存在更好的模块执行相同的任务,所以 try
block 只是简化它。最后 getpass
仍然使用完全相同的 API 提示用户输入密码,这才是您真正关心的。
关于python - 哪个是处理 ImportError - 引发错误或导入链的更好方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48481700/