gpt4 book ai didi

带有可选参数(函数)的 Python 装饰器

转载 作者:行者123 更新时间:2023-11-28 22:46:45 24 4
gpt4 key购买 nike

注意:我知道带有可选参数的装饰器包含三个嵌套函数。但是这里的可选参数是 function 本身。在将此标记为重复之前,请仔细阅读完整的帖子。我已经尝试了带有可选参数的装饰器的所有技巧,但我找不到任何将 function 作为参数的技巧。

我有一个包装错误的装饰器:

def wrap_error(func):
from functools import wraps

@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except:
import sys

exc_msg = traceback.format_exception(*sys.exc_info())
raise MyCustomError(exc_msg)

return wrapper

如果某个函数引发任何异常,它会包装错误。这个包装器的用法如下:

@wrap_error
def foo():
...

现在我想用附加的回调函数修改这个包装器,这将是可选的。我希望这个包装器用作:

@wrap_error
def foo():
...

@wrap_error(callback)
def foo():
...

我知道如何编写带有可选参数的装饰器(如果传递的参数不是函数,基于 isfunction(func) 检查包装器)。但我不确定如何处理这种情况。

注意:我可以使用@wrap_error()代替@wrap_error。此包装器用于多个包,并且不可能更新所有的更改

这是拦截器:将包装器视为:

@wrap_error(callback)               --->       foo = wrap_error(callback)(foo)
def foo():
...

所以,当 wrap_error(foo) 被执行时,我们不知道之后是否会有任何回调函数执行(如果我们只使用 @wrap_error 而不是 @wrap_error(callback))。

如果没有 (callback),wrap_error 中的包装函数将返回 func(*args.**kwargs) 以便我可以引发异常。否则我们必须返回 func 以便在下一步调用它,如果 func() 引发异常,我们调用 callback()except block 中。

最佳答案

因为很难区分decorator(func)decorator(callback),所以做两个装饰器:

from functools import wraps

class MyCustomError(Exception):
def __init__(self):
print('in MyCustomError')

# Common implementation
def wrap(func,cb=None):
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except:
if cb is not None:
cb()
raise MyCustomError()
return wrapper

# No parameters version
def wrap_error(func):
return wrap(func)

# callback parameter version
def wrap_error_cb(cb):
def deco(func):
return wrap(func,cb)
return deco

@wrap_error
def foo(a,b):
print('in foo',a,b)
raise Exception('foo exception')

def callback():
print('in callback')

@wrap_error_cb(callback)
def bar(a):
print('in bar',a)
raise Exception('bar exception')

使用 functools.wraps 检查 foo 和 bar 是否正确:

>>> foo
<function foo at 0x0000000003F00400>
>>> bar
<function bar at 0x0000000003F00598>

检查包装函数是否工作:

>>> foo(1,2)
in foo 1 2
in MyCustomError
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
File "C:\test.py", line 16, in wrapper
raise MyCustomError()
MyCustomError
>>> bar(3)
in bar 3
in callback
in MyCustomError
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
File "C:\test.py", line 16, in wrapper
raise MyCustomError()
MyCustomError

已更新

这是一种使用您请求的语法来完成此操作的方法,但我认为上面的答案更清楚。

from functools import wraps

class MyCustomError(Exception):
def __init__(self):
print('in MyCustomError')

# Common implementation
def wrap(func,cb=None):
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except:
if cb is not None:
cb()
raise MyCustomError()
return wrapper

def wrap_error(func_or_cb):
# If the function is tagged as a wrap_error_callback
# return a decorator that returns the wrapped function
# with a callback.
if hasattr(func_or_cb,'cb'):
def deco(func):
return wrap(func,func_or_cb)
return deco
# Otherwise, return a wrapped function without a callback.
return wrap(func_or_cb)

# decorator to tag callbacks so wrap_error can distinguish them
# from *regular* functions.
def wrap_error_callback(func):
func.cb = True
return func

### Examples of use

@wrap_error
def foo(a,b):
print('in foo',a,b)
raise Exception('foo exception')

@wrap_error_callback
def callback():
print('in callback')

@wrap_error(callback)
def bar(a):
print('in bar',a)
raise Exception('bar exception')

关于带有可选参数(函数)的 Python 装饰器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27167321/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com