英文:
Accessing default value of decorator argument in Python
问题
Here's the translated code without the code comments:
我正在尝试编写一个自定义的Python装饰器,它将装饰的函数包装在一个`try ... except`块中,并添加一个包含附加上下文的消息,以便更容易调试。
基于不同的资源(例如[这里](https://www.geeksforgeeks.org/decorators-with-parameters-in-python/)和[这里](https://www.freecodecamp.org/news/python-decorators-explained-with-examples/)),我到目前为止构建了以下内容:
```python
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
这按预期工作 - 如果我运行:
@_exception_handler("Foo")
def test():
raise ValueError("Bar")
test()
这会返回:
Exception: Foo: Bar
现在,我并不总是想传递自定义的msg
,因为有时这有点多余。因此,我将msg=""
设置为默认值,并且我想要检查msg==""
,如果是这种情况,我只想在装饰器内重新创建msg
,类似于msg = f"An error occurred in {func.__name__}"
。
然后,我想在没有任何msg
参数的情况下使用装饰器。我不关心空括号,对我来说使用@_exception_handler()
是完全可以的。
但是某种方式似乎不起作用:
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
如果我运行:
@_exception_handler()
def test():
raise ValueError("Bar")
test()
我会得到:
UnboundLocalError: local variable 'msg' referenced before assignment
如果我将global message
放在def decorator(func):
行的下面,我会得到相同的错误。如果我将其放在def wrapper(*args, **kwargs):
的下面,我会得到:
NameError: name 'msg' is not defined
有没有办法让这个工作?如果可能的话,我想避免使用wrapt
等第三方模块。当然,使用标准库中的functools
的wraps
也是可以的(尽管到目前为止我还没有成功)。
英文:
I am trying to write a custom Python decorator which wraps the decorated function in a try ... except
block and adds a message with additional context to make debugging easier.
Based on different resources (see here and here for example) I so far built the following:
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
This works as expected - if I run:
@_exception_handler("Foo")
def test():
raise ValueError("Bar")
test()
This returns:
Exception: Foo: Bar
Now, I do not always want to pass a custom msg
because that's sometimes a bit redundant. So I set a default value of msg=""
and I want to check if msg==""
and if that is the case I would just like to re-create the msg
inside the decorator based on the function name, something like msg = f"An error occurred in {func.__name__}"
.
I would then like to use the decorator without any msg
argument. I do not care about the empty parantheses, using @_exception_handler()
is perfectly fine for me.
But somehow this does not seem to work:
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
If I run:
@_exception_handler()
def test():
raise ValueError("Bar")
test()
I get
UnboundLocalError: local variable 'msg' referenced before assignment
If I put global message
right below the def decorator(func):
line, I get the same errors. If I put it below the def wrapper(*args, **kwargs):
, I instead get:
NameError: name 'msg' is not defined
Any ideas how I can get this to work? If possible, I would like to avoid any third-party modules such as wrapt
. Using wraps
from functools
from the standard library is fine of course (although I did not have any luck with that so far either).
答案1
得分: 5
添加这段代码 nonlocal msg
。
def _exception_handler(msg=""):
"""自定义装饰器以返回更详细的错误消息"""
def decorator(func):
def wrapper(*args, **kwargs):
nonlocal msg
try:
# 这是实际被装饰的函数
func(*args, **kwargs)
except Exception as e:
if msg == "":
# 如果没有传递自定义消息,我们只使用函数名称
msg = f"在 {func.__name__} 中发生了错误"
# 我们捕获异常并引发一个带有消息和原始异常作为原因的新异常
raise Exception(f"{msg}: {e}") from e
return wrapper
return decorator
英文:
add this code 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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论