在python中没有循环的迭代

时间:2016-01-16 22:31:08

标签: python python-2.7 dictionary iteration memo

以下示例来自Allen Downey撰写的“Think Python”一书。在解释词典中“备忘录”的概念时,他引用了下面的例子。

known = {0:0, 1:1}
def fibonacci(n):
    if n in known:
        return known[n]
    res = fibonacci(n-1) + fibonacci(n-2)
    known[n] = res
    return res
fibonacci(5)
print known

我希望这段代码返回{0:0, 1:1, 5:5},因为我没有看到任何迭代计算1到5之间的每个值的函数。但是我看到的是{0: 0, 1: 1, 2: 1, 3: 2, 4: 3, 5: 5},当代码是运行(如书所说),但我无法理解为什么函数计算表达式res = fibonacci(n-1) + fibonacci(n-2)为n = 2,n = 3和n = 4。

有人可以向我解释一下吗?我无法在书中得到解释。

2 个答案:

答案 0 :(得分:3)

尝试将print语句放入代码中以跟踪known的状态:

def fibonacci(n):
    print(n, known)
    if n in known:
        return known[n]
    res = fibonacci(n-1) + fibonacci(n-2)

    known[n] = res
    return res
fibonacci(5)
print(known)

产量

5 {0: 0, 1: 1}
4 {0: 0, 1: 1}
3 {0: 0, 1: 1}
2 {0: 0, 1: 1}
1 {0: 0, 1: 1}
0 {0: 0, 1: 1}
1 {0: 0, 1: 1, 2: 1}
2 {0: 0, 1: 1, 2: 1, 3: 2}
3 {0: 0, 1: 1, 2: 1, 3: 2, 4: 3}
{0: 0, 1: 1, 2: 1, 3: 2, 4: 3, 5: 5}

第一个(整数)值是n的值。如您所见,fibonacci(5)是 然后是fibonacci(4),然后是fibonacci(3),然后是fibonacci(2)等等 上。这些调用都是由于Python遇到

    res = fibonacci(n-1) + fibonacci(n-2)

并递归调用fibonacci(n-1)。请记住,Python会评估表达式 从左到右。因此,仅在fibonacci(n-1)返回后才fibonacci(n-2) 调用。

为了更好地理解您可以使用的递归函数调用的顺序 这个装饰者:

import functools

def trace(f):
    """This decorator shows how the function was called.
    Especially useful with recursive functions."""
    indent = ' ' * 2

    @functools.wraps(f)
    def wrapper(*arg, **kw):
        arg_str = ', '.join(
            ['{0!r}'.format(a) for a in arg]
            + ['{0} = {1!r}'.format(key, val) for key, val in kw.items()])
        function_call = '{n}({a})'.format(n=f.__name__, a=arg_str)
        print("{i}--> {c}".format(
            i=indent * (trace.level), c=function_call))
        trace.level += 1
        try:
            result = f(*arg, **kw)
            print("{i}<-- {c} returns {r}".format(
                i=indent * (trace.level - 1), c=function_call, r=result))
        finally:
            trace.level -= 1
        return result
    trace.level = 0
    return wrapper

known = {0:0, 1:1}
@trace
def fibonacci(n):
    # print(n, known)
    if n in known:
        return known[n]
    res = fibonacci(n-1) + fibonacci(n-2)

    known[n] = res
    return res
fibonacci(5)
print(known)

产生

--> fibonacci(5)                         
  --> fibonacci(4)                        # fibonacci(5) calls fibonacci(4)
    --> fibonacci(3)                      # fibonacci(4) calls fibonacci(3)
      --> fibonacci(2)                    # fibonacci(3) calls fibonacci(2)
        --> fibonacci(1)                  # fibonacci(2) calls fibonacci(1)
        <-- fibonacci(1) returns 1
        --> fibonacci(0)                  # fibonacci(2) calls fibonacci(0)
        <-- fibonacci(0) returns 0
      <-- fibonacci(2) returns 1
      --> fibonacci(1)                    # fibonacci(3) calls fibonacci(1)
      <-- fibonacci(1) returns 1
    <-- fibonacci(3) returns 2
    --> fibonacci(2)                      # fibonacci(4) calls fibonacci(2) 
    <-- fibonacci(2) returns 1
  <-- fibonacci(4) returns 3
  --> fibonacci(3)                        # fibonacci(5) calls fibonacci(3) 
  <-- fibonacci(3) returns 2
<-- fibonacci(5) returns 5
{0: 0, 1: 1, 2: 1, 3: 2, 4: 3, 5: 5}

您可以通过每个递归调用来自的缩进级别来判断。

答案 1 :(得分:0)

如您所见fibonacci是一个递归函数,这意味着它在函数内调用自身。

例如,考虑fibonacci(2)2不在known字典中,因此执行res = fibonacci(1)+fibonacci(0)。由于01已知,因此将其值(0和1)添加到res,以便res=1fibonacci(2) = 1和{2}也会添加到known中1}}字典,直到达到5.