hen*_*esu 0 python python-decorators
我正在尝试编写一个自定义 Python 装饰器,它将装饰函数包装在一个try ... except块中,并添加一条带有附加上下文的消息以使调试更容易。
基于不同的资源(例如,参见此处和此处),我到目前为止构建了以下内容:
def _exception_handler(msg):
"""Custom decorator to return a more informative error message"""
def decorator(func):
def wrapper(*args, **kwargs):
try:
# this is the actual decorated function
func(*args, **kwargs)
except Exception as e:
# we catch the exception and raise a new one with the custom
# message and the original exception as cause
raise Exception(f"{msg}: {e}") from e
return wrapper
return decorator
Run Code Online (Sandbox Code Playgroud)
这按预期工作 - 如果我运行:
@_exception_handler("Foo")
def test():
raise ValueError("Bar")
test()
Run Code Online (Sandbox Code Playgroud)
这将返回:
Exception: Foo: Bar
Run Code Online (Sandbox Code Playgroud)
现在,我并不总是想通过自定义,msg因为这有时有点多余。所以我设置了一个默认值msg="",我想检查是否msg==""是这种情况,我只想msg根据函数名称重新创建装饰器内部,例如msg = f"An error occurred in {func.__name__}".
然后我想在没有任何msg参数的情况下使用装饰器。我不关心空括号,使用@_exception_handler()对我来说完全没问题。
但不知怎的,这似乎不起作用:
Exception: Foo: Bar
Run Code Online (Sandbox Code Playgroud)
如果我运行:
def _exception_handler(msg=""):
"""Custom decorator to return a more informative error message"""
def decorator(func):
def wrapper(*args, **kwargs):
try:
# this is the actual decorated function
func(*args, **kwargs)
except Exception as e:
if msg=="":
# if no custom message is passed, we just use the function name
msg = f"An error occurred in {func.__name__}"
# we catch the exception and raise a new one with the message
# and the original exception as cause
raise Exception(f"{msg}: {e}") from e
return wrapper
return decorator
Run Code Online (Sandbox Code Playgroud)
我明白了
UnboundLocalError: local variable 'msg' referenced before assignment
Run Code Online (Sandbox Code Playgroud)
如果我把它放在global message该线的正下方def decorator(func):,我会得到同样的错误。如果我把它放在下面def wrapper(*args, **kwargs):,我会得到:
NameError: name 'msg' is not defined
Run Code Online (Sandbox Code Playgroud)
我有什么想法可以让它发挥作用吗?如果可能的话,我想避免使用任何第三方模块,例如wrapt. 使用标准库中的wrapsfromfunctools当然很好(尽管到目前为止我也没有任何运气)。
小智 5
添加此代码nonlocal msg。
def _exception_handler(msg=""):
"""Custom decorator to return a more informative error message"""
def decorator(func):
def wrapper(*args, **kwargs):
nonlocal msg
try:
# this is the actual decorated function
func(*args, **kwargs)
except Exception as e:
if msg=="":
# if no custom message is passed, we just use the function name
msg = f"An error occurred in {func.__name__}"
# we catch the exception and raise a new one with the message
# and the original exception as cause
raise Exception(f"{msg}: {e}") from e
return wrapper
return decorator
Run Code Online (Sandbox Code Playgroud)