哪个是处理ImportError的更好方法 - 引发错误或导入链?

时间:2018-01-27 23:39:36

标签: python error-handling python-import

问题

在python中遇到ImportError时,我应该直接引发错误并要求用户安装它,还是应该使用import chain?

描述

当我尝试使用lxml包来解析python中的xml文件时,我遇到了这个问题 在其官方文件中,它说:

  

如果您的代码仅使用ElementTree API并且不依赖于lxml.etree特有的任何功能,您还可以使用以下导入链的(任何部分)作为原始ElementTree的后备:< / p>

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编程中使用:

  

根据运行时导入的库定义多级功能非常有用。

但在我看来,多级功能只能通过不断检查是否已导入一个库来实现,这使得整个代码变得复杂和丑陋。

结果,我只是想知道为什么人们有时会使用这种结构,而不是直接提出错误?

2 个答案:

答案 0 :(得分:1)

首先回答你的上一个问题:

  

在python中遇到ImportError时,我应该直接引发错误并要求用户安装它,还是应该使用import chain?

您可以出于多种原因处理ImportError

  • 如果您的模块直接依赖于模块,请发生错误。如果依赖项的安装非常重要,某些库会使用有用的错误消息重新引发错误。
  • 如果您的模块试图用较慢的库代替具有相同API的更快的库,则没有理由将任何内容打印到屏幕上。
  • 如果您的模块需要某个库存在但速度明显较慢,那么您可以找到一个警告可能有用,让开发人员知道您的模块仍然可以正常运行但不会像它应该的那样快

现在提出其他问题:

  

然后导入最强大的软件包(例如lxml)不太合理,我们可以直接导入功能最少的软件包,并保存很多代码。

lxml.etreeElementTreecElementTree的特定情况下,这三者都实现了相同的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版本的后备版。

  

但是,正如在导入模块时的错误处理中所解释的那样,我发现这种方法似乎在python编程中经常使用:

您的lxml.etree示例替换速度较慢的库以获得更快的库。链接的示例代码为一堆库提供了一个通用的跨平台接口(getpass),这些库都做同样的事情(提示您输入密码)。作者处理ImportError因为这些单独的模块可能不存在,具体取决于您的操作系统。

您可以使用try和类似代码替换某些if platform.system() == 'Windows'块,但即使在单个操作系统中,也可能有更好的模块执行相同的任务,因此try阻止简化它。最后,getpass仍会提示用户输入完全相同的API密码,这是您真正关心的。

答案 1 :(得分:0)

我通常使用导入链,因为输出更受控制。

提高错误

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