Вызов функции hook каждый раз, когда возникает исключение
Скажем, я хочу иметь возможность записывать в файл каждый раз, когда любое исключение возникает в моей программе. Я не хочу изменять какой-либо существующий код.
Конечно, это может быть обобщено на возможность вставлять крючок каждый раз, когда возникает исключение.
Будет ли считаться безопасным для такого действия следующий код?
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();
Ответы
Ответ 1
Если вы хотите регистрировать неперехваченные исключения, просто используйте sys.excepthook.
Я не уверен, что вижу значение регистрации всех возбужденных исключений, так как многие библиотеки будут вызывать/ловить исключения внутри себя для вещей, которые, вероятно, вас не интересуют.
Ответ 2
Ваш код, насколько я могу судить, не сработает.
-
__init__
должен возвращать None, и вы пытаетесь вернуть экземпляр исключения резервного копирования. В общем случае, если вы хотите изменить экземпляр экземпляра при создании экземпляра класса, вы должны переопределить __new__
.
-
К сожалению, вы не можете изменить какие-либо атрибуты класса Exception
. Если бы это был вариант, вы могли бы изменить Exception.__new__
и поместили туда свой крючок.
-
трюк "global Exception
" будет работать только для кода в текущем модуле. Exception
является встроенным, и если вы действительно хотите его изменить глобально, вам нужно import __builtin__; __builtin__.Exception = MyException
-
Даже если вы изменили __builtin__.Exception
, это повлияет только на будущие использования Exception
, подклассы, которые уже были определены, будут использовать исходный класс Exception и не будут затронуты вашими изменениями. Вы можете выполнить цикл Exception.__subclasses__
и изменить __bases__
для каждого из них, чтобы вставить в него подкласс Exception
.
-
Существуют подклассы Exception
, которые также являются встроенными типами, которые вы также не можете изменить, хотя я не уверен, что вы захотите подключить их (подумайте StopIterration
).
Я думаю, что единственный достойный способ сделать то, что вы хотите, - это исправить источники Python.
Ответ 3
Этот код не будет влиять на классы исключений, которые были созданы до начала main
, и большинство исключений, которые происходят, будут такого типа (KeyError
, AttributeError
и т.д.). И вы не можете реально повлиять на эти "встроенные исключения" в самом важном смысле - если где-нибудь в вашем коде есть, например. a 1/0, реальный ZeroDivisionError будет поднят (с помощью собственных внутренних элементов Python), а не все, что вы могли бы связать с этим именем исключений.
Итак, я не думаю, что ваш код может делать то, что вы хотите (несмотря на все точки с запятой, он все еще должен быть Python, правильно?) - это может быть сделано путем исправления исходных текстов C для среды выполнения Python, по существу (например, при условии, что крюк потенциально попал в любое исключение, даже если он был позже пойман) - такого крючка в настоящее время не существует, потому что варианты использования для него были бы довольно редкими (например, a StopIteration
всегда поднимается в нормальном конец каждого цикла for
- и поймал тоже: почему на Земле кто-то хотел бы проследить это, и многие другие рутинные использования исключенных ловушек в внутренних компонентах Python и стандартной библиотеке?!).
Ответ 4
Загрузите pypy и примените его.