在装饰器中,如何将我正在装饰的函数作为参数传递?
In a decorator how can I pass the function I'm decorating as an argument?
我制作了这个简单的装饰器,它基本上将装饰函数放在 try...except
。
from functools import wraps
def try_except(on_exception=None, exception=Exception, *args, **kwargs):
from sys import stderr
def decorator(func):
@wraps(func)
def wrapper(*args1, **kwargs1):
try:
return func(*args1, **kwargs1)
except exception as e:
print(repr(e), file=stderr)
if on_exception is not None:
return on_exception(*args, **kwargs)
return wrapper
return decorator
然后,我尝试修饰下面的函数,所以它在引发 ValueError
:
时调用自身
@try_except(get_int, ValueError, "Please enter a valid integer!\n>>> ")
def get_int(prompt=">>> "):
return int(input(prompt))
但我收到以下错误:
Traceback (most recent call last):
File "C:\Python\decorator_test.py", line 9348234, in <module>
@try_except(get_int, ValueError, "Please enter a valid integer!\n>>> ")
NameError: name 'get_int' is not defined
我知道我可以将它与函数中的 try...except
放在 while
循环中,但我这样做是为了学习练习。有什么办法可以避免这种情况发生吗?
解决此问题的最佳方法是使用调用该函数的函数。
def _get_int(prompt):
get_int(prompt)
@try_except(_get_int, ValueError, "Please enter a valid integer!\n>>> ")
def get_int(prompt=">>> "):
return int(input(prompt))
del _get_int
# Or even a lambda
@try_except(lambda p: get_int(p), ValueError, "Please enter a valid integer!\n>>> ")
def get_int(prompt=">>> "):
return int(input(prompt))
因为_get_int
returns what get_int
returns 在调用的时候(也就是运行时),会变成现在的get_int
.
你可能认为没有 @
语法糖你也能做到,但那只会调用前面的(未修饰的)函数,所以它不会递归。
一种方法是定义和使用 sentinel 对象来表示“调用正在执行的相同 decorated 函数。即,在def try_except
,添加:
same = object()
并且在包装器的主体中,在 try
/except
之后:
if on_exception is not None:
if on_exception is same:
return decorator(func)(*args, **kwargs)
else:
return on_exception(*args, **kwargs)
然后,装饰函数将是例如 (Python 3,我假设,考虑到您使用 input
的方式 - 毫无疑问是 raw_input
in Python 2)...:[=18=]
@try_except(same, ValueError, "Please enter a valid integer!\n>>> ")
def get_int(prompt=">>> "):
return int(input(prompt))
我制作了这个简单的装饰器,它基本上将装饰函数放在 try...except
。
from functools import wraps
def try_except(on_exception=None, exception=Exception, *args, **kwargs):
from sys import stderr
def decorator(func):
@wraps(func)
def wrapper(*args1, **kwargs1):
try:
return func(*args1, **kwargs1)
except exception as e:
print(repr(e), file=stderr)
if on_exception is not None:
return on_exception(*args, **kwargs)
return wrapper
return decorator
然后,我尝试修饰下面的函数,所以它在引发 ValueError
:
@try_except(get_int, ValueError, "Please enter a valid integer!\n>>> ")
def get_int(prompt=">>> "):
return int(input(prompt))
但我收到以下错误:
Traceback (most recent call last):
File "C:\Python\decorator_test.py", line 9348234, in <module>
@try_except(get_int, ValueError, "Please enter a valid integer!\n>>> ")
NameError: name 'get_int' is not defined
我知道我可以将它与函数中的 try...except
放在 while
循环中,但我这样做是为了学习练习。有什么办法可以避免这种情况发生吗?
解决此问题的最佳方法是使用调用该函数的函数。
def _get_int(prompt):
get_int(prompt)
@try_except(_get_int, ValueError, "Please enter a valid integer!\n>>> ")
def get_int(prompt=">>> "):
return int(input(prompt))
del _get_int
# Or even a lambda
@try_except(lambda p: get_int(p), ValueError, "Please enter a valid integer!\n>>> ")
def get_int(prompt=">>> "):
return int(input(prompt))
因为_get_int
returns what get_int
returns 在调用的时候(也就是运行时),会变成现在的get_int
.
你可能认为没有 @
语法糖你也能做到,但那只会调用前面的(未修饰的)函数,所以它不会递归。
一种方法是定义和使用 sentinel 对象来表示“调用正在执行的相同 decorated 函数。即,在def try_except
,添加:
same = object()
并且在包装器的主体中,在 try
/except
之后:
if on_exception is not None:
if on_exception is same:
return decorator(func)(*args, **kwargs)
else:
return on_exception(*args, **kwargs)
然后,装饰函数将是例如 (Python 3,我假设,考虑到您使用 input
的方式 - 毫无疑问是 raw_input
in Python 2)...:[=18=]
@try_except(same, ValueError, "Please enter a valid integer!\n>>> ")
def get_int(prompt=">>> "):
return int(input(prompt))