访问Python中装饰器参数的默认值。

huangapple go评论95阅读模式
英文:

Accessing default value of decorator argument in Python

问题

Here's the translated code without the code comments:

  1. 我正在尝试编写一个自定义的Python装饰器它将装饰的函数包装在一个`try ... except`块中并添加一个包含附加上下文的消息以便更容易调试
  2. 基于不同的资源例如[这里](https://www.geeksforgeeks.org/decorators-with-parameters-in-python/)和[这里](https://www.freecodecamp.org/news/python-decorators-explained-with-examples/)),我到目前为止构建了以下内容
  3. ```python
  4. def _exception_handler(msg):
  5. """Custom decorator to return a more informative error message"""
  6. def decorator(func):
  7. def wrapper(*args, **kwargs):
  8. try:
  9. # this is the actual decorated function
  10. func(*args, **kwargs)
  11. except Exception as e:
  12. # we catch the exception and raise a new one with the custom
  13. # message and the original exception as cause
  14. raise Exception(f"{msg}: {e}") from e
  15. return wrapper
  16. return decorator

这按预期工作 - 如果我运行:

  1. @_exception_handler("Foo")
  2. def test():
  3. raise ValueError("Bar")
  4. test()

这会返回:

  1. Exception: Foo: Bar

现在,我并不总是想传递自定义的msg,因为有时这有点多余。因此,我将msg=""设置为默认值,并且我想要检查msg=="",如果是这种情况,我只想在装饰器内重新创建msg,类似于msg = f"An error occurred in {func.__name__}"

然后,我想在没有任何msg参数的情况下使用装饰器。我不关心空括号,对我来说使用@_exception_handler()是完全可以的。

但是某种方式似乎不起作用:

  1. def _exception_handler(msg=""):
  2. """Custom decorator to return a more informative error message"""
  3. def decorator(func):
  4. def wrapper(*args, **kwargs):
  5. try:
  6. # this is the actual decorated function
  7. func(*args, **kwargs)
  8. except Exception as e:
  9. if msg=="":
  10. # if no custom message is passed, we just use the function name
  11. msg = f"An error occurred in {func.__name__}"
  12. # we catch the exception and raise a new one with the message
  13. # and the original exception as cause
  14. raise Exception(f"{msg}: {e}") from e
  15. return wrapper
  16. return decorator

如果我运行:

  1. @_exception_handler()
  2. def test():
  3. raise ValueError("Bar")
  4. test()

我会得到:

  1. UnboundLocalError: local variable 'msg' referenced before assignment

如果我将global message放在def decorator(func):行的下面,我会得到相同的错误。如果我将其放在def wrapper(*args, **kwargs):的下面,我会得到:

  1. NameError: name 'msg' is not defined

有没有办法让这个工作?如果可能的话,我想避免使用wrapt等第三方模块。当然,使用标准库中的functoolswraps也是可以的(尽管到目前为止我还没有成功)。

英文:

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:

  1. def _exception_handler(msg):
  2. """Custom decorator to return a more informative error message"""
  3. def decorator(func):
  4. def wrapper(*args, **kwargs):
  5. try:
  6. # this is the actual decorated function
  7. func(*args, **kwargs)
  8. except Exception as e:
  9. # we catch the exception and raise a new one with the custom
  10. # message and the original exception as cause
  11. raise Exception(f"{msg}: {e}") from e
  12. return wrapper
  13. return decorator

This works as expected - if I run:

  1. @_exception_handler("Foo")
  2. def test():
  3. raise ValueError("Bar")
  4. test()

This returns:

  1. 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:

  1. def _exception_handler(msg=""):
  2. """Custom decorator to return a more informative error message"""
  3. def decorator(func):
  4. def wrapper(*args, **kwargs):
  5. try:
  6. # this is the actual decorated function
  7. func(*args, **kwargs)
  8. except Exception as e:
  9. if msg=="":
  10. # if no custom message is passed, we just use the function name
  11. msg = f"An error occurred in {func.__name__}"
  12. # we catch the exception and raise a new one with the message
  13. # and the original exception as cause
  14. raise Exception(f"{msg}: {e}") from e
  15. return wrapper
  16. return decorator

If I run:

  1. @_exception_handler()
  2. def test():
  3. raise ValueError("Bar")
  4. test()

I get

  1. 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:

  1. 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

  1. def _exception_handler(msg=""):
  2. """自定义装饰器以返回更详细的错误消息"""
  3. def decorator(func):
  4. def wrapper(*args, **kwargs):
  5. nonlocal msg
  6. try:
  7. # 这是实际被装饰的函数
  8. func(*args, **kwargs)
  9. except Exception as e:
  10. if msg == "":
  11. # 如果没有传递自定义消息,我们只使用函数名称
  12. msg = f"在 {func.__name__} 中发生了错误"
  13. # 我们捕获异常并引发一个带有消息和原始异常作为原因的新异常
  14. raise Exception(f"{msg}: {e}") from e
  15. return wrapper
  16. return decorator
英文:

add this code nonlocal msg.

  1. def _exception_handler(msg=""):
  2. """Custom decorator to return a more informative error message"""
  3. def decorator(func):
  4. def wrapper(*args, **kwargs):
  5. nonlocal msg
  6. try:
  7. # this is the actual decorated function
  8. func(*args, **kwargs)
  9. except Exception as e:
  10. if msg=="":
  11. # if no custom message is passed, we just use the function name
  12. msg = f"An error occurred in {func.__name__}"
  13. # we catch the exception and raise a new one with the message
  14. # and the original exception as cause
  15. raise Exception(f"{msg}: {e}") from e
  16. return wrapper
  17. return decorator

huangapple
  • 本文由 发表于 2023年5月25日 23:35:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/76334025.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定