Как «украсить» функцию на сайте вызова, а не определение - PullRequest
0 голосов
/ 23 апреля 2020

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

def state_on_exc(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        try:
            result = f(*args, **kwargs)
            return result
        except Exception as e:
            ex_type, exc_value, tb = sys.exc_info()
            if tb is not None:
                prev = tb
                curr = tb.tb_next
                while curr is not None:
                    prev = curr
                    curr = curr.tb_next
                print(prev.tb_frame.f_locals)
            raise e

@state_on_exc
def apply(f):
    return f

def myfunc():
    a = 5
    raise ValueError

apply(myfunc())

Но оболочка, похоже, не вызывается при исключении (она была специально поднята в myfunc()) - она ​​не печатает никаких локальных переменных. Есть ли какой-то правильный способ добиться того же или лучший способ сделать это?

1 Ответ

1 голос
/ 23 апреля 2020

Довольно близко.

  1. Вам необходимо вернуть упакованную функцию из декоратора.
  2. Для повторного повышения не следует добавлять объект исключения в stmt повышения.
  3. Чтобы украсить функцию, передайте объект функции функции декоратора.
  4. Чтобы вызвать декорированную функцию, вызовите декорированную функцию. А не неукрашенная функция.

Пример:

from functools import wraps

def decorate(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        try:
            return f(*args, **kwargs)
        except Exception as e:
            # handle exception
            print("handled exception:", type(e))
            # re-raise
            raise
    return wrapper

def myfunc():
    a = 5
    raise ValueError

decorated_fun = decorate(myfunc)
decorated_fun()

Вывод:

$ python3 test.py
handled exception: <class 'ValueError'>
Traceback (most recent call last):
  File "tt.py", line 25, in <module>
    decorated_fun()
  File "tt.py", line 7, in wrapper
    result = f(*args, **kwargs)
  File "tt.py", line 22, in myfunc
    raise ValueError
ValueError
...