Как продолжить выполнение кадра из последней попытки инструкции после обработки исключения?

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

Следующий псевдокод должен иллюстрировать мои потребности.

 def function(): return missing_var try: print function() except NameError: frame = inspect.trace()[-1][0] # inject missing variable frame.f_globals["missing_var"] = ... # continue frame execution from last attempted instruction exec frame.f_code from frame.f_lasti 

Прочтите все unittest на repl.it

Заметки

  • Как указал Иван-Поздеев в своем ответе , это называется возобновлением .
  • После дальнейших исследований я нашел ответ Veedrac на вопрос « Возобновить программу на номер строки в контексте перед исключением, используя специальный файл sys.excepthook, опубликованный lc2817, очень интересный. Он полагается на работу Ричи Хиндла.

Задний план

Код работает в подчиненном процессе, который контролируется родителем. Задачи (функции действительно) записываются в родительском, а последние передаются ведомому с использованием укропа . Я ожидаю, что некоторые задачи (работающие в подчиненном процессе) попытаются получить доступ к переменным из внешних областей в родительском элементе, и я хотел бы, чтобы подчиненный запрашивал эти переменные родителям на лету.

ps: Я не ожидаю, что эта магия будет работать в производственной среде.

3 Solutions collect form web for “Как продолжить выполнение кадра из последней попытки инструкции после обработки исключения?”

В отличие от того, что говорят разные комментаторы, в Python возможна обработка исключений «возобновление на ошибку». Библиотека fuckit.py реализует указанную стратегию. Это ошибки паролей, переписывая исходный код вашего модуля во время импорта, вставляя try...except блоков вокруг каждого оператора и проглатывая все исключения. Так, возможно, вы могли бы попробовать подобную тактику?

Само собой разумеется, что библиотека предназначена как шутка. Никогда не используйте его в производственном коде.


Вы упомянули, что ваш прецедент – это уловка ссылок на пропущенные имена. Вы думали об использовании метапрограммирования для запуска своего кода в контексте «умного» пространства имен, такого как defaultdict ? (Это, пожалуй, чуть менее плохая идея, чем fuckit.py .)

 from collections import defaultdict class NoMissingNamesMeta(type): @classmethod def __prepare__(meta, name, bases): return defaultdict(lambda: "foo") class MyClass(metaclass=NoMissingNamesMeta): x = y + "bar" # y doesn't exist >>> MyClass.x 'foobar' 

NoMissingNamesMeta – это метакласс – языковая конструкция для настройки поведения оператора class . Здесь мы используем метод __prepare__ для настройки словаря, который будет использоваться в качестве пространства имен класса во время создания класса. Таким образом, поскольку мы используем defaultdict вместо обычного словаря, класс, чей метакласс – NoMissingNamesMeta , никогда не получит NameError . Любые имена, упомянутые во время создания класса, будут автоматически инициализированы до "foo" .

Этот подход аналогичен идее @ AndréFratelli о ручном запросе лениво инициализированных данных из объекта Scope . В производстве я бы сделал это, а не это. Версия метакласса требует меньше ввода текста для написания кода клиента, но за счет гораздо большего количества магии. (Представьте себе, что вы отлаживаете этот код через два года, пытаясь понять, почему несуществующие переменные динамически вносятся в сферу применения!)

Техника обработки исключений «возобновления» оказалась проблематичной , поэтому ее не хватает на языках C ++ и более поздних.

Лучше всего использовать цикл while, чтобы не возобновить, где было исключено исключение, а скорее повторить из заданного места:

 while True: try: do_something() except NameError as e: handle_error() else: break 

Вы действительно не можете размотать стек после исключения, поэтому вам придется иметь дело с проблемой перед вами. Если ваше требование состоит в том, чтобы генерировать эти переменные «на лету» (что не рекомендуется, но, похоже, вы это понимаете), тогда вам нужно будет их действительно запросить. Вы можете реализовать механизм для этого (например, иметь глобальный экземпляр класса Scope и переопределять __getitem__ или использовать что-то вроде функции __dir__ ), но не так, как вы просите об этом.

  • функция seek ()?
  • Обновление списка в кортеже
  • Почему Python не обнаруживает ошибки перед выполнением?
  • Python Как проверить, достиг ли последний элемент в цепочке инструментов итератора?
  • Как получить текущее доменное имя с помощью Python / GAE?
  • Как работает Python .join?
  • Создание записи в хранилище данных приводит к зашифрованным свойствам при просмотре в браузере
  • Случайное генерирование математических вопросов
  • Python - лучший язык программирования в мире.