繁体   English   中英

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

[英]Which is the better way to handle ImportError - Raise error or import chain?

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

描述

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

如果您的代码仅使用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:
        ...

在我看来,导入替代品不是一个好主意,因为:
如果您可以导入另一个库作为替代库,而该库可能不具有lxml的所有方法,则所有脚本只能基于所有软件包中的那些可用方法

然后,导入最强大的程序包(例如此处的lxml)变得没有意义,我们可以直接导入功能最差的程序包,并节省很多代码。 或者,如果以后要使用其他方法,则应直接引发ImportError。

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

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

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

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

首先要回答您的最后一个问题:

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

您可以处理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所有功能。 这就是为什么使用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因为根据您的操作系统,这些单独的模块可能不存在。

您可以使用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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM