语句装饰器
Statement decorators
我们有一些代码如下所示:
from third_party_library import foo
for n in range(3):
try:
foo(args)
break
except:
print "Retry %i / 3" % n
我想使用装饰器,让我们的代码更简洁,看起来像这样:
from third_party_library import foo
@retry(3)
foo(args)
这给出了语法错误。我是不是遗漏了什么,或者 python 只是不允许在语句上使用装饰器?
Python 不允许在语句上使用装饰器;它们只允许在 class 和函数定义中使用。您可以在 the grammar specification.
的顶部附近看到它
装饰器只能应用于函数和class 定义,例如:
@decorator
def func():
...
@decorator
class MyClass(object):
...
您不能在该语言的其他任何地方使用它们。
要执行您想要的操作,您可以制作一个普通的 retry
函数并将 foo
和 args
作为参数传递。实现看起来像这样:
def retry(times, func, *args, **kwargs):
for n in xrange(times):
try:
func(*args, **kwargs)
break
except Exception: # Try to catch something more specific
print "Retry %i / %i" % (n, times)
装饰器是在 Python 2.4 中引入的。最初,它们仅支持函数和方法声明 (PEP 318)。
Python 3 将它们扩展为 class 声明 (PEP 3129).
任何其他语言构造都不支持装饰器。
装饰器确实不能应用于语句,你可以按照另一个答案中描述的重试功能。然而,在我看来,还有一种更像 Python 的方法,即使用上下文管理器。让我以可运行的方式重新表述您的问题,让代码说话:
import random
def foo():
"""The function you were importing, now runnable"""
n = random.randint(1,10)
print "Got", n,
if n < 8:
raise Exception("Failed")
for n in range(3):
try:
foo()
break
except:
print "Retry %i / 3" % n
使用(自动生成的)ContextManager,代码将如下所示:
import random
def foo():
"""The function you were importing, now runnable"""
n = random.randint(1,10)
print "Got", n,
if n < 8:
raise Exception("Failed")
from contextlib import contextmanager
@contextmanager
def retry():
"""Something similar to a decorator for statements"""
try:
yield
except:
print "Retry %i / 3" % n
for n in range(3):
with retry():
foo()
break
如您所见,解决方案并不完美,因为 ContextManager 可以恰好执行语句一次(在产生时打开),而不是在循环中。然而,至少对于这个简单的例子,对我来说似乎更清楚,即使循环必须在外部完成。详情见https://docs.python.org/2.7/library/contextlib.html and https://docs.python.org/2/reference/datamodel.html#context-managers
装饰器本身就是包装函数(以参数为函数)和return新函数的函数;
因此您可以像这样内联使用它:
retry(3)(foo)(args)
#retry(3) is function accept function
#retry(3)(foo) return the new function
#then u exploit the function by call with the `args`
我们有一些代码如下所示:
from third_party_library import foo
for n in range(3):
try:
foo(args)
break
except:
print "Retry %i / 3" % n
我想使用装饰器,让我们的代码更简洁,看起来像这样:
from third_party_library import foo
@retry(3)
foo(args)
这给出了语法错误。我是不是遗漏了什么,或者 python 只是不允许在语句上使用装饰器?
Python 不允许在语句上使用装饰器;它们只允许在 class 和函数定义中使用。您可以在 the grammar specification.
的顶部附近看到它装饰器只能应用于函数和class 定义,例如:
@decorator
def func():
...
@decorator
class MyClass(object):
...
您不能在该语言的其他任何地方使用它们。
要执行您想要的操作,您可以制作一个普通的 retry
函数并将 foo
和 args
作为参数传递。实现看起来像这样:
def retry(times, func, *args, **kwargs):
for n in xrange(times):
try:
func(*args, **kwargs)
break
except Exception: # Try to catch something more specific
print "Retry %i / %i" % (n, times)
装饰器是在 Python 2.4 中引入的。最初,它们仅支持函数和方法声明 (PEP 318)。
Python 3 将它们扩展为 class 声明 (PEP 3129).
任何其他语言构造都不支持装饰器。
装饰器确实不能应用于语句,你可以按照另一个答案中描述的重试功能。然而,在我看来,还有一种更像 Python 的方法,即使用上下文管理器。让我以可运行的方式重新表述您的问题,让代码说话:
import random
def foo():
"""The function you were importing, now runnable"""
n = random.randint(1,10)
print "Got", n,
if n < 8:
raise Exception("Failed")
for n in range(3):
try:
foo()
break
except:
print "Retry %i / 3" % n
使用(自动生成的)ContextManager,代码将如下所示:
import random
def foo():
"""The function you were importing, now runnable"""
n = random.randint(1,10)
print "Got", n,
if n < 8:
raise Exception("Failed")
from contextlib import contextmanager
@contextmanager
def retry():
"""Something similar to a decorator for statements"""
try:
yield
except:
print "Retry %i / 3" % n
for n in range(3):
with retry():
foo()
break
如您所见,解决方案并不完美,因为 ContextManager 可以恰好执行语句一次(在产生时打开),而不是在循环中。然而,至少对于这个简单的例子,对我来说似乎更清楚,即使循环必须在外部完成。详情见https://docs.python.org/2.7/library/contextlib.html and https://docs.python.org/2/reference/datamodel.html#context-managers
装饰器本身就是包装函数(以参数为函数)和return新函数的函数;
因此您可以像这样内联使用它:
retry(3)(foo)(args)
#retry(3) is function accept function
#retry(3)(foo) return the new function
#then u exploit the function by call with the `args`