每次引发exception时调用一个钩子函数
比方说,我希望能够每次在我的程序中的任何地方引发exception时logging文件。 我不想修改任何现有的代码。
当然,这可以概括为能够在每次引发exception时插入钩子。
下面的代码会被认为是安全的做这样的事情?
class MyException(Exception): def my_hook(self): print('---> my_hook() was called'); def __init__(self, *args, **kwargs): global BackupException; self.my_hook(); return BackupException.__init__(self, *args, **kwargs); def main(): global BackupException; global Exception; BackupException = Exception; Exception = MyException; raise Exception('Contrived Exception'); if __name__ == '__main__': main();
如果你想logging未捕获的exception,只需使用sys.excepthook即可 。
我不确定我看到logging所有引发的exception的价值,因为许多库会在内部提升/捕获exception,因为你可能不会在乎。
我所知道的代码是行不通的。
-
__init__
必须返回None,并且您试图返回备份exception的实例。 一般来说,如果您想要更改在实例化类时返回的实例,则应该覆盖__new__
。 -
不幸的是,你不能改变
Exception
类的任何属性。 如果这是一个选项,你可以改变Exception.__new__
并把你的钩子放在那里。 -
“
global Exception
”技巧只适用于当前模块中的代码。Exception
是一个内build的,如果你真的想要全局改变它,你需要import __builtin__; __builtin__.Exception = MyException
import __builtin__; __builtin__.Exception = MyException
-
即使你改变了
__builtin__.Exception
它只会影响Exception
将来使用,已经定义的子类将使用原来的Exception类,并且不会受到你的改变的影响。 您可以遍历Exception.__subclasses__
__bases__
,并为其中的每一个更改__bases__
以在其中插入您的Exception
子类。 -
还有一些
Exception
子类也是内build的types,你也不能修改,虽然我不确定你想要钩住它们中的任何一个(认为StopIterration
)。
我认为唯一可行的方法就是修补Python源代码。
这段代码不会影响在main
开始之前创build的任何exception类,而且大部分发生的exception都是这种types( KeyError
, AttributeError
等等)。 从最重要的意义上说,你不能真正影响这些“内置的exception” – 如果你的代码中的任何地方是例如1/0, 真正的 ZeroDivisionError将被引发(由Python自己的内部), 而不是你可能已经绑定了这个例外的名字。
所以,我不认为你的代码可以做你想做的事情(尽pipe所有的分号,它仍然是Python,对吧?) – 它可以通过修补Python运行时的C源,本质上(例如通过提供一个可能被任何exception捕获的钩子,即使它后来被捕获) – 这样的钩子当前不存在,因为它的用例将是非常罕见的(例如, StopIteration
总是在每个for
循环的正常结束- 也被抓到了;为什么在地球上会想要追踪这个 ,以及在Python内部和标准库中捕获exception的许多其他常规用法?!)。
下载pypy和仪器。