Сохранение неизменяемой переменной, необходимой в более высокой области, при возникновении ошибки

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

Иногда может возникнуть серьезная ошибка, которая должна полностью прервать обработку этой итерации. Это нежелательно, но ожидаемо. В этом случае в качестве возврата выбирается время по умолчанию.

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

Я могу придумать 2 реализации:

  • Перехватите ошибку, верните ее вместе с переменной и повторно вызовите ее, прерывая более широкий рабочий контекст:

    def foo(new_process_time):
        condition = True
        e = None
        try:
            new_process_time = 10  # Calculated within foo() through context only available in foo()
            if condition:
                raise ValueError("Stuff broke.")
            ...  # logic I wish to abort if an exception is raised
        except ValueError as e:
            print('Error triggered')
            return new_process_time, e
        return new_process_time, e
    
    
    def worker():
        new_process_time = None
        try:
            new_process_time, e = foo(new_process_time)
            if e is not None:
                raise e
            ...  # logic I wish to abort if an exception is raised
        except Exception as e:
            print(f"Logging the exception: {e}")
        finally:
            if new_process_time is not None:
                print(f"Next schedule: {new_process_time}")
            else:
                print(f"Next schedule: DEFAULT")
    
    worker()
    
  • Используйте генератор:

    def foo_2(new_process_time):
        condition = True
        try:
            new_process_time = 10  # Calculated within foo() through context only available in foo()
            yield new_process_time
            if condition:
                raise ValueError("Stuff broke.")
            ...  # logic I wish to abort if an exception is raised
        except ValueError as e:
            print('Error triggered')
            raise e
    
    
    def worker_2():
        new_process_time = None
        try:
            try:
                foo_gen = foo_2(new_process_time)
                new_process_time = next(foo_gen)  # handle the logic up to new_process_time
                next(foo_gen)  # handle the rest of the logic
            except StopIteration:
                print('this is fine, continue as normal')
            ...  # logic I wish to abort if an exception is raised
        except Exception as e:
            print(f"Logging the exception: {e}")
        finally:
            if new_process_time is not None:
                print(f"Next schedule: {new_process_time}")
            else:
                print(f"Next schedule: DEFAULT")
    
    worker_2()
    

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

В качестве альтернативы, я считаю, что global здесь может быть вариантом, но учитывая множество причин избегать его. Я полагаю, что если рабочая функция выполняется параллельно, это может вызвать проблемы.

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

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Поместите неизменяемую переменную в изменяемый блок:

from dataclasses import dataclass

@dataclass
class TimeContext:
    new_process_time: int | None = None

Тогда foo не нужно беспокоиться об ошибках.

def foo(time_context: TimeContext):
    condition = True

    time_context.new_process_time = 10  # this is reflected in the outer function
    if condition:
        raise ValueError("Stuff broke.")

И worker не нужно разворачивать ошибки:

def worker():
    time_context = TimeContext()
    try:
        foo(time_context)
    except Exception as e:
        print(f"Logging the exception: {e}")
    finally:
        if time_context.new_process_time is not None:
            print(f"Next schedule: {time_context.new_process_time}")
        else:
            print(f"Next schedule: DEFAULT")

Думаю, мой вопрос на самом деле сводится к тому, что «тип данных неизменяем, что теперь?» такой простой ответ, как «сделать его изменчивым», просто потрясающий. Позвольте мне протестировать это в моей более широкой реализации, чтобы убедиться, что это работает.

Floriancitt 20.08.2024 16:02

Другие вопросы по теме