4.6.栈帧:实现递归

假设不是将递归调用的结果与来自 convertString 的字符串拼接到 toStr,我们修改了算法,以便在进行递归调用之前将字符串入栈。此修改的算法的代码展示在 ActiveCode 1 中。

  1. from pythonds.basic.stack import Stack
  2. rStack = Stack()
  3. def toStr(n,base):
  4. convertString = "0123456789ABCDEF"
  5. while n > 0:
  6. if n < base:
  7. rStack.push(convertString[n])
  8. else:
  9. rStack.push(convertString[n % base])
  10. n = n // base
  11. res = ""
  12. while not rStack.isEmpty():
  13. res = res + str(rStack.pop())
  14. return res
  15. print(toStr(1453,16))

ActiveCode 1

每次我们调用 toStr,我们在栈上推入一个字符。回到前面的例子,我们可以看到在第四次调用 toStr 之后,栈看起来像 Figure 5 。注意,现在我们可以简单地将字符从栈中弹出,并将它们连接成最终结果 “1010”。

4.6.栈帧:实现递归.figure5

Figure 5

前面的例子让我们了解了 Python 如何实现一个递归函数调用。 当在 Python 中调用函数时,会分配一个栈来处理函数的局部变量。当函数返回时,返回值留在栈的顶部,以供调用函数访问。 Figure 6 说明了第 4 行返回语句后的调用栈。

4.6.栈帧:实现递归.figure6

Figure 6

注意,对 toStr(2//2,2) 的调用在栈上返回值为 “1”。 然后,在表达式 “1” + convertString[2%2] 中使用此返回值替换函数调用(toStr(1,2)),这将在栈顶部留下字符串 “10”。 这样,Python 调用栈就代替了我们在 Listing 4 中明确使用的栈。在我们的列表求和示例中,你可以认为栈上的返回值取代了累加器变量。

栈帧还为函数使用的变量提供了一个作用域。 即使我们重复地调用相同的函数,每次调用都会为函数本地的变量创建一个新的作用域。