使用importlib.import_module处理从导入的模块引发的异常

时间:2019-10-12 19:46:30

标签: python python-3.x plugins python-import python-importlib

我有一个简单的插件系统,下面是简化形式。想法是,插件将实现一个抽象类,并且可以引发异常以发出拆卸信号。

# my_plugin.py
import my_app


class MyPlugin(my_app.MyPluginBase):

    def start(self):
        raise my_app.MyLibException()
# my_app.py
import abc
import importlib


class MyLibException(Exception):
    pass


class MyPluginBase(abc.ABC):

    @abc.abstractmethod
    def start(self):
        pass


def main():
    module = importlib.import_module('my_plugin')
    klass = getattr(module, 'MyPlugin')
    try:
        app = klass()
        app.start()
    except MyLibException as e:
        print('ok')
        print(e.__class__)
    except Exception as e:
        print('not ok')
        print(e.__class__)


if __name__ == '__main__':
    main()

在上面运行会导致:

not ok
<class 'my_app.MyLibException'>

在这种情况下处理异常的正确方法是什么?我想在except MyLibException as e:而不是except Exception as e:处捕获引发的异常。

1 个答案:

答案 0 :(得分:1)

此问题的根本原因是MyLibException__main__中被识别为my_app.py的属性,但是在my_plugin.py中将其导入时是{ {1}}。

最干净的解决方案是将my_app与其他模块分开,以完全避免循环依赖,但是由于您在注释中提到这不是一种选择,因此我唯一想到的方法是导入同一文件中的异常。显然,这不是一个好习惯,但是对于一般的循环进口也可以这样说。

实现此目标的几种方法是:

  1. 通过将MyLibException(或import my_app)添加到 import __main__ as my_app并使用my_app.py
  2. 捕获异常
  3. 通过像导入except my_app.MyLibException一样使用importlibmy_plugin 并采用与1中相同的方式。
  4. my_app = importlib.import_module('my_app')在定义from __main__ import MyLibException之后,但是违反了PEP8,其中指出:

      

    导入总是放在文件的顶部,在任何模块注释和文档字符串之后,在模块全局变量和常量之前。

有关可能不是一个好主意的更多建议和原因,请参见: