【问题标题】:Checking module name inside 'except ImportError'检查“除了 ImportError”中的模块名称
【发布时间】:2016-06-24 09:29:39
【问题描述】:
try:
   import MySQLdb
   # some action
except ImportError as err:
   # fallback code

PyCharm 对此给出代码检查警告:

try 块中的'MySQLdb' 和 'except ImportError' 也应该在 except 块中定义

此检查检测应解析但未解析的名称。由于动态调度和鸭子类型,这在有限但有用的情况下是可能的。顶级项和类级项的支持优于实例项。

好的,我认为警告是合理的,因为fallback code 假定未安装“MySQLdb”,而可能是一些不同的错误刚刚引发了 ImportError。所以我使用了类似的东西:

try:
   import MySQLdb
   # some action
except ImportError as err:
   if "MySQLdb" in repr(err):
       # fallback code
   else:
       raise

PyCharm 警报仍然存在,但可能只是 PyCharm 问题(谷歌显示此类检查存在问题)

问题:

  1. 当您“除了 ImportError”时,是否真的值得检查名称?即使在简单的情况下(import MySQLdb 之后没有some action)?

  2. 如果值得检查,上面的例子是正确的方法吗?如果没有 - 正确的方法是什么?

P.S. MySQLdb 只是系统中可能不存在的模块的一个示例。

【问题讨论】:

标签: python exception-handling pycharm importerror


【解决方案1】:

在 Python 3.3+ 中,ImportError 具有属性 name,它告诉导入失败的模块的名称。那么 MySQLdb 当然会暗示你被 Python 2 困住了。

【讨论】:

    【解决方案2】:

    我认为你误解了警告,如果你没有在 except 块中定义一个名为 MySQLdb 的变量,那么稍后当你尝试使用该模块时,你会得到一个 NameError

    try:
        import foo
    except ImportError:
        pass
    
    foo.say_foo() #foo may or may not be defined at this point!
    

    如果该模块仅在try: 子句中使用,那么这没有问题。但对于更一般的情况,检查器希望您在 except 块中定义变量:

    try:
        import foo
    except ImportError:
        foo = None  #now foo always exists
    
    if foo: #if the module is present
        foo.say_foo()
    else:
        print("foo") #backup use
    

    如果该模块仅在 try 块中使用,那么您可以通过从命名空间中删除该模块来向检查器(和您自己)表明您以后不能使用该模块:

    try:
        import foo
    except ImportError:
        pass
    else:
        # if it was able to import use it then get rid of the local variable
        foo.do_thing()
        del foo #optional module should not be relied on outside 
     
    
    # now foo never exists here, checker is happy.
    

    【讨论】:

    • 可能你是对的......在我的上下文中,我只是不认为问题出在命名错误上,因为我在后备中实际做的是... connection_string.replace("mysql://", "mysql+mysqlconnector://"),所以我的想法离得太远了命名错误。
    • 如果您以后不使用该模块,则将其从名称空间中删除以向 pycharm(以及您自己,这样您就不会遇到 NameError)表明它仅用于一部分
    • 在我的几个具有此类功能的函数中,如果我无法导入库,我只需return。我想这也是可以接受的行为。
    【解决方案3】:

    试试这个:

    try:
      import libname
    except ImportError as e:
           e = e[0][16:]
           print("\n[!] Error: Please Install Module Name:[ {} ] And Try Again !!!".format(e))
           exit(1)
    

    输出:

    [!] 错误:请安装模块名称:[libname] 并重试!!!

    【讨论】:

    • 当python版本更改错误信息时会发生什么? (以前发生过)。而且...感谢您在此答案上投入时间,但此答案不适用于此问题。
    【解决方案4】:

    已经提到的一种获取名称的方法是使用name 属性:

    try:
        import pty
    except ImportError as e:
        print(e.name)
    

    但是,重要的是要注意您可能无法获得您开始使用的模块名称;也就是说,在 Windows 上运行上述代码会给你termios 作为输出,而不是pty

    为了保持与 python 2.7 的兼容性(对于那些尚未进行切换的人,您在 clock 上)

    try:
        import pty
    except ImportError as e:
        print(e.args[0].rsplit(' ',1)[-1])  # `msg` attribute is `message` on python2...stick with args
    
    # prints the same result: termios
    


    一些奖金花絮:
    • Python 3.6 于 2016 年底左右发布。由于是 2019+,您可以选择更清晰的例外ModuleNotFoundError

      ImportError 的子类,在找不到模块时由 import 引发。当在 sys.modules 中找到 None 时也会引发它。

    • 如果您使用的是 Python 3.3+,请不要忘记 path 属性(除了已经提到的 name),它提供了引发异常的任何文件的路径(仅有用在更复杂的情况下——在我给path 的简单示例中,将返回None。)

    【讨论】:

      猜你喜欢
      • 2018-09-04
      • 1970-01-01
      • 2017-06-30
      • 1970-01-01
      • 2011-12-19
      • 2015-08-25
      • 2018-02-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多