哪个是处理 ImportError - 引发错误或导入链的更好方法?
Which is the better way to handle ImportError - Raise error or import chain?
问题
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。
但是,如 导入模块时的错误处理中的回答
,我发现这种方法似乎在 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
示例将较慢的库替换为较快的库。链接的示例代码为一堆库定义了一个通用的跨平台接口 (getpass
),这些库都做同样的事情(提示您输入密码)。作者处理 ImportError
是因为这些单独的模块可能不存在,具体取决于您的操作系统。
您可以用 if platform.system() == 'Windows'
和类似代码替换一些 try
块,但即使在单个 OS 中也可能有更好的模块执行相同的任务,因此 try
块只是简化它。最后 getpass
仍然提示用户使用完全相同的密码 API,这是您真正关心的。
我一般使用导入链,因为输出更可控
引发错误
Traceback (most recent call last):
File "core.py", line 1, in <module>
ImportError: <error description>
导入链
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
问题
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。
但是,如 导入模块时的错误处理中的回答 ,我发现这种方法似乎在 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
示例将较慢的库替换为较快的库。链接的示例代码为一堆库定义了一个通用的跨平台接口 (getpass
),这些库都做同样的事情(提示您输入密码)。作者处理 ImportError
是因为这些单独的模块可能不存在,具体取决于您的操作系统。
您可以用 if platform.system() == 'Windows'
和类似代码替换一些 try
块,但即使在单个 OS 中也可能有更好的模块执行相同的任务,因此 try
块只是简化它。最后 getpass
仍然提示用户使用完全相同的密码 API,这是您真正关心的。
我一般使用导入链,因为输出更可控
引发错误
Traceback (most recent call last):
File "core.py", line 1, in <module>
ImportError: <error description>
导入链
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