[英]Which is the better way to handle ImportError - Raise error or import chain?
When encounter ImportError in python, should I directly raise the error and ask the user to install it, or should I use import chain? 当在python中遇到ImportError时,我应该直接引发错误并要求用户安装它,还是应该使用导入链?
I came across this question when I tried to use lxml package to parse xml file in python. 当我尝试使用lxml包解析python中的xml文件时遇到了这个问题。
In its official documentation, it says: 在其官方文档中说:
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:
如果您的代码仅使用ElementTree API,并且不依赖于lxml.etree特有的任何功能,则还可以使用以下导入链(的任何部分)作为原始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:
...
It seems to me that it's a bad idea to import a substitution since: 在我看来,导入替代品不是一个好主意,因为:
if you can import another library as a substitution, which may not have all the methods as lxml, then all your script can only based on those available methods in all the packages . 如果您可以导入另一个库作为替代库,而该库可能不具有lxml的所有方法,则所有脚本只能基于所有软件包中的那些可用方法 。
Then it make less sense to import the most powerful package (eg lxml here), we could directly import the least functional one, and save a lot codes. 然后,导入最强大的程序包(例如此处的lxml)变得没有意义,我们可以直接导入功能最差的程序包,并节省很多代码。 Or if we want to use additional methods later, we then should directly raise the ImportError.
或者,如果以后要使用其他方法,则应直接引发ImportError。
However, as answered in Error handling when importing modules , I find this approach seems to be used frequently in python programming: 但是,正如导入模块时的错误处理中所回答的那样,我发现这种方法似乎在python编程中经常使用:
it's useful to define multi-level functionality based on what library has been imported in runtime.
根据在运行时导入的库定义多级功能非常有用。
But it seems to me that, the multi-level functionality can only be achieved by constantly checking whether one library has been imported, which makes the whole codes complicated and ugly. 但是在我看来,只能通过不断检查是否已导入一个库来实现多级功能,这会使整个代码变得复杂而丑陋。
As a result, I just wondered why people sometimes use such structure, instead of raise the error directly? 结果,我只是想知道为什么人们有时会使用这种结构,而不是直接引发错误?
To answer your last question first: 首先要回答您的最后一个问题:
When encounter ImportError in python, should I directly raise the error and ask the user to install it, or should I use import chain?
当在python中遇到ImportError时,我应该直接引发错误并要求用户安装它,还是应该使用导入链?
You can handle ImportError
s for many reasons: 您可以处理
ImportError
的原因很多:
Now for your other questions: 现在,对于您的其他问题:
Then it make less sense to import the most powerful package (eg lxml here), we could directly import the least functional one, and save a lot codes.
然后,导入最强大的程序包(例如此处的lxml)变得没有意义,我们可以直接导入功能最差的程序包,并节省很多代码。
In the specific case of lxml.etree
, ElementTree
, and cElementTree
, all three implement the same API. 在
lxml.etree
, ElementTree
和cElementTree
的特定情况下,所有三个都实现相同的API。 They're substitutes for one another. 他们是彼此的替代品。
ElementTree
is pure-Python and will always work, but cElementTree
is usually present and is faster. ElementTree
是纯Python的,将始终运行,但是cElementTree
通常存在并且速度更快。 lxml.etree
is even faster but is an external module. lxml.etree
甚至更快,但它是一个外部模块。
Think of it like this: 这样想:
try:
import super_fast_widget as widget
except ImportError:
try:
import fast_widget as widget
except ImportError:
import slow_widget as widget
From your code's perspective, widget
will always work the same regardless of which library actually ended up getting imported, so it's best to try to import the fastest implementation and fall back on slower ones if performance is something you care about. 从代码的角度来看,无论最终导入哪个库,
widget
都将始终工作相同,因此,如果您在乎性能,那么最好尝试导入最快的实现,而退回到较慢的实现。
You are correct in that you can't fully utilize all of lxml
's features if you allow fallback libraries. 正确的是,如果允许使用回
lxml
,则无法充分利用lxml
的所有功能。 This is why lxml.etree
is being used instead of just lxml
. 这就是为什么使用
lxml.etree
而不是lxml
。 It intentionally mimics the API of the other two libraries. 它有意模仿其他两个库的API。
Here's a similar example from Django's codebase: 这是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 internally does this for a lot of built-in modules. Python内部为许多内置模块执行此操作。 There's a slower, pure Python version that's used as a fallback for the faster C version.
有一个较慢的纯Python版本,用作较快的C版本的后备。
However, as answered in Error handling when importing modules , I find this approach seems to be used frequently in python programming:
但是,正如导入模块时的错误处理中所回答的那样,我发现这种方法似乎在python编程中经常使用:
Your lxml.etree
example substituted slower libraries for faster ones. 您的
lxml.etree
示例将较慢的库替换为较快的库。 The linked example code defines a common, cross-platform interface ( getpass
) to a bunch of libraries that all do the same thing (prompt you for your password). 链接的示例代码为一堆相同的库定义了一个通用的跨平台接口(
getpass
)(提示您输入密码)。 The author handles the ImportError
s because those individual modules may not exist depending on your operating system. 作者处理
ImportError
因为根据您的操作系统,这些单独的模块可能不存在。
You could replace some of the try
blocks with if platform.system() == 'Windows'
and similar code, but even among a single OS there may be better modules that perform an identical task so the try
blocks just simplify it. 您可以使用
if platform.system() == 'Windows'
和类似的代码替换某些try
块,但是即使在单个OS中,也可能会有更好的模块执行相同的任务,因此try
块只是对其进行了简化。 In the end getpass
still prompts the user for their password with the exact same API, which is all you really care about. 最后,
getpass
仍会使用完全相同的API提示用户输入密码,这是您真正关心的全部。
I usually use import chains because the output is more controlled. 我通常使用导入链,因为输出受到更多控制。
Raising Errors 引发错误
Traceback (most recent call last):
File "core.py", line 1, in <module>
ImportError: <error description>
Import Chains 进口链
i Importing "lxml.etree"
x Error Importing "lxml.etree"
i Importing "xml.etree.cElementTree" on Python 2.5+
x Error Importing "xml.etree.cElementTree" on Python 2.5+
i Please Install "lxml.etree" or "xml.etree.xElementTree" on Python 2.5+
i Exit with code 1
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.