我制作了这个简单的装饰器,基本上将装饰的功能放在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
我知道我可以把它放在函数中while
的{{1}}循环中,但我这样做是为了学习练习。有没有办法让这件事发生?
答案 0 :(得分:1)
解决此问题的最佳方法是使用调用函数的函数。
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
会返回get_int
在通话时返回的内容(即运行时),因此会更改为get_int
当前的内容。
你可能认为没有@
语法糖就可以做到这一点,但这只会调用前一个(未修饰的)函数,所以它不会递归。
答案 1 :(得分:1)
一种方法是定义并使用 sentinel 对象来表示&#34;调用现在正在执行的相同修饰函数。即,在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
的方式 - 毫无疑问在Python 2中是raw_input
)...:
@try_except(same, ValueError, "Please enter a valid integer!\n>>> ")
def get_int(prompt=">>> "):
return int(input(prompt))