2016-05-07 2 views
0

Одна лекции Design of Computer Program на Udacity просит осуществить декоратор прослеживать рекурсии:Ненужных примерки наконец

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

Попытка поднять исключение в вашем 'методе fib'. – totoro

ответ

0

Попробуйте этот метод fib и посмотрите разницу.

@trace 
def fib(n): 
    if n == 0 or n == 1: 
     raise RuntimeError('Test') 
    else: 
     return fib(n-1) + fib(n-2) 

«попробуй, наконец,» гарантирует, что код в блоке, наконец, по-прежнему выполняется во стек разматывания, вызванный исключением.

Редактировать

В вашем случае нет необходимости в этом, но это, как правило, хорошая практика.

Редактировать для @Rahn

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 

против

result = f(*args) 
print '%s<-- %s == %s' % ((trace.level-1)*indent, signature, result) 
trace.level -= 1 
+0

Кажется, что ваш 'fib' производит одинаковый вывод внутри или без' try-finally' – Wentao

+0

Кажется, что OP знает, что делает 'try..finally' - он просто сказал, что не видит смысла использовать эту конструкцию _ в этом случае_ , Честно говоря, я тоже. – TigerhawkT3

+0

@Rahn Визуально, да. – totoro

Смежные вопросы