关于Udacity的Design of Computer Program的一个讲座要求实现装饰器来跟踪递归:
from functools import update_wrapper
def decorator(d):
"Make function d a decorator: d wraps a function fn."
def _d(fn):
return update_wrapper(d(fn), fn)
update_wrapper(_d, d)
return _d
@decorator
def trace(f):
indent = ' '
def _f(*args):
signature = '%s(%s)' % (f.__name__, ', '.join(map(repr, args)))
print '%s--> %s' % (trace.level*indent, signature)
trace.level += 1
try:
# your code here
print '%s<-- %s == %s' % ((trace.level-1)*indent, signature, result)
finally:
# your code here
return # your code here
trace.level = 0
return _f
@trace
def fib(n):
if n == 0 or n == 1:
return 1
else:
return fib(n-1) + fib(n-2)
fib(4)
我将代码填入trace
函数并且它可以工作:
@decorator
def trace(f):
indent = ' '
def _f(*args):
signature = '%s(%s)' % (f.__name__, ', '.join(map(repr, args)))
print '%s--> %s' % (trace.level*indent, signature)
trace.level += 1
try:
result = f(*args)
print '%s<-- %s == %s' % ((trace.level-1)*indent, signature, result)
finally:
trace.level -= 1
return result
trace.level = 0
return _f
输出:
--> fib(4)
--> fib(3)
--> fib(2)
--> fib(1)
<-- fib(1) == 1
--> fib(0)
<-- fib(0) == 1
<-- fib(2) == 2
--> fib(1)
<-- fib(1) == 1
<-- fib(3) == 3
--> fib(2)
--> fib(1)
<-- fib(1) == 1
--> fib(0)
<-- fib(0) == 1
<-- fib(2) == 2
<-- fib(4) == 5
但很快我发现trace
可以没有try-finally
:
@decorator
def trace(f):
indent = ' '
def _f(*args):
signature = '%s(%s)' % (f.__name__, ', '.join(map(repr, args)))
print '%s--> %s' % (trace.level*indent, signature)
trace.level += 1
result = f(*args)
print '%s<-- %s == %s' % ((trace.level-1)*indent, signature, result)
trace.level -= 1
return result
trace.level = 0
return _f
输出完全相同。
在这种情况下,我没有看到try-finally
的任何意义。有人可以向我解释一下吗?
答案 0 :(得分:0)
尝试使用此fib
方法并查看差异。
@trace
def fib(n):
if n == 0 or n == 1:
raise RuntimeError('Test')
else:
return fib(n-1) + fib(n-2)
“try-finally”确保在由异常引起的堆栈展开期间仍然执行finally块中的代码。
修改强>
在你的情况下没有必要,但这通常是一种很好的做法。
@ pahn的编辑
try:
result = f(*args)
print '%s<-- %s == %s' % ((trace.level-1)*indent, signature, result)
finally:
print '%s<-- %s == Exception' % ((trace.level-1)*indent, signature)
trace.level -= 1
VS
result = f(*args)
print '%s<-- %s == %s' % ((trace.level-1)*indent, signature, result)
trace.level -= 1