【问题标题】:Friendlier error messages on import for missing modules缺少模块的导入时更友好的错误消息
【发布时间】:2017-05-03 13:15:36
【问题描述】:

如果用户尝试运行尝试导入尚未安装的模块的 python 脚本,我想实现一些更友好的错误消息。这包括打印出有关如何安装缺少的模块的说明。

这样做的一种方法是在导入周围放置一个 try..catch 块,但这有点难看,因为它会变得像这样简单

import some_module

进入

try:
  import some_module
except ImportError, e:
  handle_error(e)

它必须添加到每个文件中。此外, ImportError 似乎没有将丢失模块的名称存储在任何地方(消息中除外),因此如果您需要知道名称(就像我一样),您必须在每个导入周围放置一个单独的 try..catch .解析模块的名称不是选项,因为 ImportError 携带的消息可能会因 python 版本而异,具体取决于用户的语言环境。

我想我可以使用 sys.excepthook 来捕获所有异常并传递除了 ImportError 之外的那些异常。 或者是否可以定义类似的东西

safe_import some_module

这会像我想要的那样吗?

有人知道这个问题的任何现有解决方案吗?

【问题讨论】:

    标签: python exception-handling


    【解决方案1】:

    您可以将它放在始终执行的位置(例如在 site.py 或 sitecustomize.py 中):

    import __builtin__
    
    realimport = __builtin__.__import__
    
    def myimport(modname, *a):
      try:
        return realimport(modname, *a)
      except ImportError, e:
        print "Oops, couldn't import %s (%s)" % (modname, e)
        print "Here: add nice directions and whatever else"
        raise
    
    __builtin__.__import__ = myimport
    

    请参阅__import__ 文档here

    【讨论】:

    • 我想这样做的一个问题是,如果其他人提出相同的想法,它就不能很好地发挥作用。如果其他一些包使用相同的技巧,那么你就不走运了(因为如果 import 它将安装另一个版本)。
    【解决方案2】:

    您不必为每次导入都捕获 ImportError。您可以在脚本的入口点使用全局 try..except 块。

    您可以使用 message 属性从 ImportError 实例中获取缺失模块的名称。

    例如,如果您的脚本的入口点是 main.py:

    if __name__ == '__main__':
        try:
            import module1
            import module2
    
            module1.main()
         except ImportError as error:
            print "You don't have module {0} installed".format(error.message[16:])
    

    不要在try..except 块之外导入任何内容。这将涵盖 module1 和 module2 以及它们导入的所有模块等等。

    如您所说,您可以定义自己的import_safe 函数:

    def import_safe(module):
        try:
            return __import__(module)
        except ImportError as error:
            print "You don't have module {0} installed".format(error.message[16:])
    

    然后就可以使用函数了:

    sys = import_safe('sys')
    gtk = import_safe('gkt')
    

    在我看来,拳头策略更好。第二个会使您的代码难以阅读。并且会改变语言的一个重要部分。

    【讨论】:

    • 第一种方法的问题是它试图解析错误消息(甚至不是,它只是假设模块名称位于特定位置)。这根本不是一个可以做出的假设:错误消息可能是本地化的或在 python 版本之间发生变化
    • 而不是 print "You don't have module {0} installed".format(error.message[16:]) 只是 print(error) 适用于 2.7.10 和 3.5.0
    【解决方案3】:

    我会将其他模块放入包中,当导入这些模块时,会打印出更有用的消息,然后引发常规 ImportError。安装真正的模块后,您的模块将被隐藏(确保将它们所在的目录添加到 sys.path 的 end)。

    【讨论】:

    • 我认为这可能是最好的解决方案。它不依赖于任何特殊的“技巧”,因此应该非常强大。同时它不需要对源代码进行任何更改(除了可能将正确的路径添加到 sys.path 可以轻松处理)。
    【解决方案4】:

    替换sys.excepthook:

    orig_excepthook = sys.excepthook
    
    def my_excepthook(type, value, tb):
        orig_excepthook(type, value, tb)
        if issubclass(type, ImportError):
            # print some friendly message
    
    sys.excepthook = my_excepthook
    

    【讨论】:

      猜你喜欢
      • 2018-06-22
      • 2020-11-03
      • 2010-10-14
      • 2012-08-08
      • 1970-01-01
      • 2019-02-13
      • 2020-01-30
      • 1970-01-01
      相关资源
      最近更新 更多