我有一个简单的插件系统,下面是简化形式。想法是,插件将实现一个抽象类,并且可以引发异常以发出拆卸信号。
# 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:
处捕获引发的异常。
答案 0 :(得分:1)
此问题的根本原因是MyLibException
在__main__
中被识别为my_app.py
的属性,但是在my_plugin.py
中将其导入时是{ {1}}。
最干净的解决方案是将my_app
与其他模块分开,以完全避免循环依赖,但是由于您在注释中提到这不是一种选择,因此我唯一想到的方法是导入同一文件中的异常。显然,这不是一个好习惯,但是对于一般的循环进口也可以这样说。
实现此目标的几种方法是:
MyLibException
(或import my_app
)添加到
import __main__ as my_app
并使用my_app.py
except my_app.MyLibException
一样使用importlib
:my_plugin
并采用与1中相同的方式。 my_app = importlib.import_module('my_app')
在定义from __main__ import MyLibException
之后,但是违反了PEP8,其中指出:
导入总是放在文件的顶部,在任何模块注释和文档字符串之后,在模块全局变量和常量之前。
有关可能不是一个好主意的更多建议和原因,请参见: