Вызов функции ловушки каждый раз, когда возникает исключение - PullRequest
12 голосов
/ 23 июня 2009

Допустим, я хочу иметь возможность регистрировать в файл каждый раз, когда возникает любое исключение, где-нибудь в моей программе. Я не хочу изменять какой-либо существующий код.

Конечно, это можно обобщить, чтобы иметь возможность вставлять хук каждый раз, когда возникает исключение.

Будет ли следующий код считаться безопасным для таких действий?

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();

Ответы [ 4 ]

14 голосов
/ 23 июня 2009

Если вы хотите регистрировать необнаруженных исключений, просто используйте sys.excepthook .

Я не уверен, что вижу значение ведения журнала всех повышенных исключений, так как многие библиотеки будут вызывать / ловить исключения внутри себя для вещей, которые вам, вероятно, не нужны.

9 голосов
/ 23 июня 2009

Ваш код, насколько я могу судить, не будет работать.

  1. __init__ должен вернуть None, и вы пытаетесь вернуть экземпляр исключения из резервной копии. В общем, если вы хотите изменить экземпляр, возвращаемый при создании экземпляра класса, вы должны переопределить __new__.

  2. К сожалению, вы не можете изменить какие-либо атрибуты класса Exception. Если бы это был вариант, вы могли бы изменить Exception.__new__ и поместить туда свой крючок.

  3. трюк "global Exception" будет работать только для кода в текущем модуле. Exception является встроенным, и если вы действительно хотите изменить его глобально, вам нужно import __builtin__; __builtin__.Exception = MyException

  4. Даже если вы изменили __builtin__.Exception, это повлияет только на будущее использование Exception, подклассы, которые уже были определены, будут использовать исходный класс Exception и не будут затронуты вашими изменениями. Вы можете зациклить Exception.__subclasses__ и изменить __bases__ для каждого из них, чтобы вставить туда свой подкласс Exception.

  5. Существуют подклассы Exception, которые также являются встроенными типами, которые вы также не можете изменить, хотя я не уверен, что вы захотите подключить любой из них (подумайте StopIterration).

Я думаю, что единственный достойный способ сделать то, что вы хотите, - это исправить исходники Python.

5 голосов
/ 23 июня 2009

Этот код не повлияет на любые классы исключений, которые были созданы до начала main, и большинство возникающих исключений будут таких типов (KeyError, AttributeError и т. Д.). И вы не можете реально влиять на эти «встроенные исключения» в самом важном смысле - если где-то в вашем коде есть, например. 1/0, real ZeroDivisionError будет сгенерирован (собственными внутренностями Python), не , что бы вы ни связали с именем этого исключения.

Итак, я не думаю, что ваш код может делать то, что вы хотите (несмотря на все точки с запятой, он по-прежнему должен быть Python, верно?) - это можно сделать, исправив исходники C для среды выполнения Python, по сути (например, путем предоставления хука, потенциально перехваченного для любого исключения, даже если он будет перехвачен позднее) - такого хука в настоящее время не существует, поскольку варианты его использования были бы довольно редкими (например, StopIteration всегда поднимается в нормальном конце каждого цикла for - и тоже перехватывается, зачем на Земле хотеть отследить , что , и многие другие рутинные использования перехваченных исключений во внутренних компонентах Python и стандартная библиотека?!).

0 голосов
/ 23 июня 2009

Скачать pypy и обработать его.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...