跳转至

高级函数 — 嵌套、分层与递归

单个函数只是零件,这一章教你把零件组装成机器。 三种组装方式: 嵌套(函数的产出直接喂给下一个函数,省掉中间变量)、分层(大任务 拆成一层层小函数,主函数当调度室)、递归(函数调用自己,把问题 越拆越小)。第三种是全书的智力高峰。

1. 这一章在全书链条里的位置

读法建议:这一章的三个概念有明确的难度台阶——嵌套是「第 09 章的自然延伸」 (你已经在 print(input()) 里用过),分层是「组织方法的升级」,递归是 「全新的思维方式」。前两个小时内能上手,第三个值得慢慢啃: 递归学不明白不碍着继续往后读,它和第三部分的数据结构配合时才会真正发力。

第 09 章解决「造零件」,这一章解决「组机器」。组装方式决定了程序能长多大: 嵌套让单行代码更有表达力,分层让程序能扩张到几十上百个函数而不乱, 递归则打开了「循环写起来别扭、但问题自己会分叉」的那一类问题。 本章末尾的部分导读预告了第三部分的战场:列表、元组、集合、字典1—— 数据结构登场后,递归和分层会有真正的用武之地(树的遍历就是递归的主场)。

2. 顶层全景:三种组装方式一张图

  嵌套    f(g(h(x)))      值从最内层往外层层加工,一行读完一条流水线
  分层    main() → 子函数A → 子函数B   主函数只管调度,每个子函数只管一段
  递归    f(大问题) → f(小问题) → … → f(基准情形)  自己调用自己,直到够小直接答

  图说:嵌套是「纵向压缩」,分层是「横向分工」,递归是「自我相似」。

3. 核心原理一:嵌套调用 — 流水线式的一行代码

定义:一个函数的返回值立即作为下一个函数的输入2。书里的四个例子 由浅入深3:

print(input('Enter your name: '))       # input 的产出直接喂给 print
result = abs(round(-4.567))             # round 得 -5,abs 得 5 → result = 5
print(len(str(12345)))                  # str 得 '12345',len 得 5

第三行的方法链值得多看一眼:

msg = '   hello, World! '
cleaned_msg = msg.strip().capitalize().replace('world', 'there')
# 剥空白 → 'hello, World!' → 首字母大写 → 'Hello, World!' → 替换 → 'Hello, there!'

msg.strip().capitalize().replace(...) 这种链式调用是嵌套的专用形态: 每个方法对前一个的产出再加工,像工厂流水线4。好处原书列了三条: 省中间变量、逻辑顺序与阅读顺序一致、单行内完成一串操作2。

代价也要知道(我们的补充):链太长时出错难定位——五六个环节串一行, 中间某环产出不对,你得拆开才能看。实务的止损线大约三环,再长就拆成 带名字的中间变量。

练习把嵌调用用到了实战强度。Calculator 题要求六个函数接力: arithmetic() 调 get_number() 问数、再把结果喂给 sum/substract/ product/divide——输入 2 和 3,输出四行算式(2.0 + 3.0 = 5.0 等)5。 Statistics 题多了一层:avg(x, y, z) 的内部是 total(x, y, z) / 3——函数的生产线里又套着函数;stats() 再把 五个零件全部调度起来,输入 1、2、3,一行输出 1.0 2.0 3.0 min: 1.0 max: 3.0 total: 6.0 average: 2.06。 这两道题其实就是下一节「分层」的雏形:一个主函数,几个专职零件。

4. 核心原理二:分层函数 — 大任务切成层级

定义:把大任务拆成小任务,每个小任务一个专职函数,主函数只负责调度7。 书里的完整案例是学生成绩系统,五个函数分成三层:

  最底层(干具体活的零件)
    calculate_average(g1, g2, g3)  —— 算平均分
    assign_letter_grade(average)   —— 分档 A/B/C/D/F(第 07 章成绩链的函数版)
    print_results(name, avg, grade)—— 打印一行结果

  中间层(流程组装)
    process_single_student()       —— 问名字、问三科成绩,调上面三个零件,交一份结果

  最上层(调度入口)
    process_student_grades()       —— while True 循环调中间层,问「继续吗」,
                                       不答 yes 就 break

  图说:调用关系自顶向下(主 → 中间 → 零件),数据自底向上回流(零件的 return
  一层层交回主函数)。书里的运行演示:Alice 三科 95/99/100 → 平均 98.00 得 A;
  答 yes 继续,Bob 80/90/100 → 90.00 也得 A;答 no 收工[^8]。

拿第一轮(Alice,95/99/100)走一遍调用链,分层的「调度感」立刻具体:

  process_student_grades()          ← 最上层:进循环
    └─ process_single_student()     ← 中间层:问名字和三科
         ├─ input × 4(名字 + 三科成绩)
         ├─ calculate_average(95, 99, 100) → 294/3 = 98.0
         ├─ assign_letter_grade(98.0)       → 'A'(第 1 档就中,链止)
         └─ print_results('Alice', 98.0, 'A') → 打印 Student:Alice, ...
    └─ 问「继续吗」→ yes → 第二轮(Bob,80/90/100 → 90.0 → 'A')
    └─ 问「继续吗」→ no → break,程序收工

  图说:每一层只往下调一层、只收下一层的 return;没人越级。
  这就是「分层」两个字在运行时的样子。

分层的收益原书给了三个词:可读性、可维护性、模块化7。拆开了看: assign_letter_grade 只关心分档规则,哪天规则改了(比如 85 分以上算 A), 只动这一个函数,其他四层无感——这就是第 09 章「单一职责」原则在 多函数规模下的兑现。主函数 process_student_grades 读起来像 流程说明书:循环、问人、判断继续——一行行都是「调度」,没有一行在 「算数」。

5. 核心原理三:递归 — 函数调用自己

定义:递归(recursion)是函数直接调用自己的编程技术——把问题拆成 更小的同类子问题,子问题用同一个函数解决9。每个递归函数必须有 两个零件,缺一不可9:

零件 作用 类比
基准情形(base case) 递归停止的条件,防止无限循环 俄罗斯套娃的最小那只:打不开,直接看
递归情形(recursive case) 函数调用自己,但输入更小或更简单 每开一层,里面还是套娃,但小了一号

主线例子:factorial(5) 的全程展开

阶乘是最经典的递归第一课——n! = n × (n-1) × … × 1,而它的定义 本身就是递归的:n! = n × (n-1)!,只有 0! = 1! = 1 是例外。 书里的代码恰好两分支对应两个零件10:

def factorial(n):
  if n == 0 or n == 1:    # 基准情形:小到不用乘了,直接答 1
    return 1
  else:                   # 递归情形:n! = n × (n-1)!
    return n * factorial(n - 1)

print(factorial(5))       # 输出 120

拿 factorial(5) 把展开过程一层层摊开——注意每层都在等里层的答案:

  第 1 层  factorial(5)  →  5 × factorial(4)   ← 先挂着,去算 factorial(4)
  第 2 层  factorial(4)  →  4 × factorial(3)   ← 挂着
  第 3 层  factorial(3)  →  3 × factorial(2)   ← 挂着
  第 4 层  factorial(2)  →  2 × factorial(1)   ← 挂着
  第 5 层  factorial(1)  →  基准情形,直接 return 1

  然后答案逐层回流:
  第 4 层拿到 1:2 × 1 = 2        → 交回第 3 层
  第 3 层拿到 2:3 × 2 = 6        → 交回第 2 层
  第 2 层拿到 6:4 × 6 = 24       → 交回第 1 层
  第 1 层拿到 24:5 × 24 = 120    → 交还给最初的调用处 ✓(5! = 120 验算无误)

  图说:递归 = 「下钻五层、回卷五层」。每层函数没死,只是暂停在等答案;
  这就是为什么缺了基准情形会永远下钻(无限递归),缺了递归情形就答不了大问题。

数位数与回文的逐步展开

digits(2022) 只下钻四层,适合再练一遍手12:

  digits(2022) → 1 + digits(202)   ← 2022 // 10 = 202,末位 2 被砍掉
  digits(202)  → 1 + digits(20)
  digits(20)   → 1 + digits(2)
  digits(2)    → 基准:n < 10,return 1
  回卷:1 + (1 + (1 + 1)) = 4 ✓(2022 是四位数)

  图说://10 每砍一刀,问题规模小一位,位数加一。

palindrome('adccda') 的展开展示了「两把刀」的配合12:

  palindrome('adccda')  首尾 a…a 相同 → 递归 'dccd'
  palindrome('dccd')    首尾 d…d 相同 → 递归 'cc'
  palindrome('cc')      首尾相同     → 递归 ''
  palindrome('')        基准:len ≤ 1,return True ✓
  若中途首尾不同(如 'adba' 的 a…b),当场 return False,不再下钻。

间接递归与练习的递归家族

书里还点了间接递归(a 调 b、b 调 a 形成循环)的名,例子 function_a(5) 的输出是 None——因为 a(5)→b(4)→a(2)→b(1)→a(-1), 此时所有 if 都不成立,没有 return 语句兜底,默认交还 None11。 这个 None 顺便复习了第 09 章的旧知识:函数没有 return,就交还 None。

练习四题,各是递归的一个典型形态12:

  • fib(4) 斐波那契:fib(n) = fib(n-1) + fib(n-2),基准 fib(0)=0, fib(1)=1。 注意它是两次自调——每层分叉两支,递归树比阶乘的链条复杂得多;
  • digits(2022) 数位数:1 + digits(n // 10)——每次砍掉末位,n < 10 时 基准返回 1。整除 // 在这里是「缩小问题的刀」;
  • palindrome('ada') 回文:比首尾字符,相同就递归到 s[1:-1](掐头去尾), 长度 ≤ 1 时基准为 True。切片 s[1:-1] 是「缩小问题的另一把刀」;
  • count_ways(4) 爬楼梯:n 级台阶每次走 1 或 2 步,多少种走法—— 答案是 count_ways(n-1) + count_ways(n-2)(最后一步的两种迈法), 基准 n=0 或 1 时各 1 种;count_ways(4) 输出 5。 它和 fib 同构,是「递归类面试题」的标准形态。

6. fib 的递归树:为什么「两次自调」是质变

阶乘每层只调自己一次,链条是线性的;fib 每层调两次,链条分叉成树。 拿 fib(4) 看全树(每个节点的值 = 两个子节点之和)14:

                        fib(4)
                       /      \
                fib(3)        fib(2)
                /    \        /    \
          fib(2)  fib(1)  fib(1)  fib(0)
          /    \     1       1       0
      fib(1) fib(0)
         1      0

  数叶子:1 + 0 + 1 + 1 + 0 = 3?不对——逐节点求和:
  fib(2) = 1+0 = 1;fib(3) = fib(2)+fib(1) = 1+1 = 2;
  fib(4) = fib(3)+fib(2) = 2+1 = 3 ✓(斐波那契数列第 4 项是 3)

  图说:fib(2) 被算了两遍,fib(1) 被算了三遍——重复计算随 n 指数增长。
  这就是 §7 边界节说的性能暗坑:代码美如画,复杂度烂如泥。

树里的重复一目了然,这就是递归的完整图景:优雅与低效可以共存。 修复手段(记忆化:算过的存进字典,第 14 章的知识)能把这棵树剪回线性—— 但那是下一本书的内容,这里的任务是「看见」这个结构。

7. 递归与循环:同一个任务的两种身法

GenAI 互动区第一问就是「递归和迭代(循环)有什么不同」15—— 正文没答,我们用阶乘把两种身法并排演一遍:

# 递归身法:问题自己定义自己
def factorial(n):
  if n == 0 or n == 1:
    return 1
  return n * factorial(n - 1)

# 循环身法:一个累乘器转圈
def factorial(n):
  result = 1
  for i in range(2, n + 1):
    result *= i
  return result

两个版本对 factorial(5) 都交还 120。判据一句话:问题本身是递归定义 的(阶乘、斐波那契、树的结构),递归版本往往更短更贴题;问题本质是 「重复做同一件事」(遍历、累加),循环版本更直白更高效。 入门阶段两个都该会写——能互译,才算真正拥有这道题的两种视角。

8. 作者的判断与证据

判断(我们的,不是书里的): 三种组装方式里,分层是唯一 「用了就回不去」的一种——嵌套写长了会拆,递归能不用就不用(循环往往 更快),但分层是程序规模增长的唯一通道:五十个函数的程序不靠分层 组织,就是一堆无法维护的代码。本章最值得带走的不是递归的优雅, 是成绩系统那张五函数三层图。 如果错,会错在: 超小规模的脚本(几十行)里,分层是过度设计—— 三个函数也要分三层,反而徒增跳转。分层的收益随规模增长, 程序越大越对,程序越小越可以平铺。

  • 三种组织方式的排列(嵌套 → 分层 → 递归)难度递进,符合「先值后术」的 教学法;分层案例(成绩系统)是全章写得最好的代码,五函数三层职责分明, 值得当模板抄一遍8。
  • 递归一节保持了入门书少见的克制:只讲 direct/indirect 之分和两个 必备零件,没有展开递归树、调用栈、复杂度——对零基础读者是对的, 但你要心里有数:递归的真实成本(重复计算,如 fib 会指数级地重算 子问题)本书未提,GenAI 互动区也只问了「递归深度限制」13。
  • 章节定位上,本章是第二部分的收官:函数从「单个零件」进化成「组织方式」, 而第三部分的数据结构将给这些组织方式提供真正的舞台1。

9. 分层与数据结构的关系:预告

本章末尾的部分导读把第三部分的四种数据结构(列表、元组、集合、字典) 与函数并排放,不是排版巧合1:函数是处理动作,数据结构是处理对象, 两者合起来才是完整的数据处理。成绩系统案例里已经有这个配对的雏形—— print_results 打印的三个值(name, average, grade),在真实程序里 会被收进一个列表或字典,而不是散在三个变量里。 学完第 11–14 章回来重构这个案例:用一个列表装所有学生的记录, 用循环遍历它、用函数处理每条记录——那才是数据处理程序的标准形态。 把这句话记住,第三部分的四章就有了统一的读法:每章都在回答 「这个结构擅长装什么、配上函数能干什么」。

10. 边界与局限

先放一句本章的「出门提示」:嵌套、分层、递归在真实代码里的使用频率 并不均等——分层天天用,嵌套常见,递归少见。如果你的目标是把 Python 当数据处理工具用,分层和嵌套是必须熟练的体力活,递归了解 形态、能读懂即可;如果将来要啃算法课,递归才会从「了解」升级成 「精通」。

  • 递归的「最大深度」只在 GenAI 区提了名字13:Python 默认约一千层 下钻就报 RecursionError 强制停止——防止无限递归把内存撑爆的保险丝。 阶乘、fib 这种「每层一挂」的递归,几十层就到顶;真需要更深的, 要么改循环,要么显式调大限额(进阶话题)。
  • fib 的低效没被点破。 fib(4) 会重复计算 fib(2) 两次; fib(30) 的重复计算是指数级。工程上要么用循环、要么用「记忆化」 (把算过的存下来)——本书给了递归的形态,没给递归的性能观; 第六章的递归树展开图(§6)就是这道题的完整答案。
  • 没有 try-except,分层的输入校验依旧缺席。 成绩系统问成绩时 敲字母,照样 ValueError 暴毙——第 06 章的免责声明在这里依然生效。 值得注意:分层结构给校验留好了位置——process_single_student 的 三个 input 各自套一个「问+验」小函数,就是工程里的标准做法; 书没走这一步,但结构已经在了。
  • Calculator 练习里有个拼写地雷:substract(双 s)。 原书在 函数定义和调用处都错得一致,所以程序能跑16——但「定义和调用 错得一致」恰恰是最危险的错误形态:它工作正常,直到某天你想用正确的 拼写 subtract 调它。自己写代码时,函数名拼错会立刻 NameError, 反倒是保护。
  • 间接递归的例子输出 None 还有一个隐藏信息: a、b 两个函数互相 调用的链条 a(5)→b(4)→a(2)→b(1)→a(-1) 里,b(1) 调用 a(-1) 时 n > 0 为假,直接「掉出函数底」——没有 else、没有 return, Python 在函数末尾自动补 return None。每个无 return 函数的 脚底都踩着这样一个隐形的 return None11。
  • 间接递归的例子输出 None,书没解释为什么11。谜底是第 09 章的 「无 return 则返回 None」,只是 a、b 两函数在 n <= 0 时都没有 return 语句——正好是一题多考。
  • 分层案例没有对应的练习。 嵌套有 Calculator/Statistics 两题, 递归有四题,唯独分层只有成绩系统一个演示、没有跟练——想学透, 得自己把第 06 章的收银或第 08 章的成绩册重构成三层函数, 这个空白我们用 §9 的预告和可带走清单补上了方向。

11. 可带走的

  1. 嵌套调用 = 上一环的产出直接当下环的输入;方法链是其专用形态, 可读性止损线大约三环23。
  2. 分层 = 主函数调度、子函数专职;改一处不动全局,单一职责的规模化78。
  3. 递归两零件:基准情形(停)与递归情形(缩小再自调),缺一不可; 缺基准永远下钻(无限递归),缺递归情形答不了大问题9。
  4. factorial 的展开图:下钻五层、回卷五层,每层在等里层的答案; 5! = 120,手算可验10。
  5. 递归的三种「缩小刀」:n-1(阶乘)、n//10(数位数)、s[1:-1](回文)12。
  6. 无 return 交还 None——每个函数脚底都踩着一个隐形的 return None, 间接递归例子的谜底就是它11。
  7. 递归默认有深度保险丝(约一千层,RecursionError 触发),真深了换循环13。
  8. 成绩系统五函数三层,调度只往下调一层、只收下一层 return—— 分层模板的范本,值得默写8。
  9. 递归与循环可以互译;问题递归定义用递归,重复操作用循环15。
  10. 函数是动作、数据结构是对象,两者配对才是数据处理(第三部分预告)1。

12. 原文地图

主题 原书章 原文位置
本章定位与三部分预告 CHAPTER 10: Advanced Functions text/19-ch10-chapter-10-advanced-functions.txt:5(搜「organized in a professional manner」) · text/19-ch10-chapter-10-advanced-functions.txt:392(搜「Data Structures」)
嵌套调用的定义与收益 同上 text/19-ch10-chapter-10-advanced-functions.txt:14(搜「output of one function」)
四个嵌套示例 同上 text/19-ch10-chapter-10-advanced-functions.txt:23(搜「print(input」) · text/19-ch10-chapter-10-advanced-functions.txt:32(搜「abs(round(-4.567))」) · text/19-ch10-chapter-10-advanced-functions.txt:39(搜「strip().capitalize()」) · text/19-ch10-chapter-10-advanced-functions.txt:48(搜「len(str(12345))」)
Calculator 练习 同上 text/19-ch10-chapter-10-advanced-functions.txt:66(搜「def get_number」) · text/19-ch10-chapter-10-advanced-functions.txt:95(搜「2.0 + 3.0 = 5.0」)
Statistics 练习(avg 套 total) 同上 text/19-ch10-chapter-10-advanced-functions.txt:135(搜「def avg」) · text/19-ch10-chapter-10-advanced-functions.txt:153(搜「min: 1.0」)
分层函数的定义 同上 text/19-ch10-chapter-10-advanced-functions.txt:158(搜「hierarchical functions」)
成绩系统案例与运行 同上 text/19-ch10-chapter-10-advanced-functions.txt:169(搜「calculate_average」) · text/19-ch10-chapter-10-advanced-functions.txt:222(搜「Alice」)
递归定义与两零件 同上 text/19-ch10-chapter-10-advanced-functions.txt:271(搜「function calls itself」) · text/19-ch10-chapter-10-advanced-functions.txt:277(搜「base case」)
阶乘与间接递归 同上 text/19-ch10-chapter-10-advanced-functions.txt:284(搜「def factorial」) · text/19-ch10-chapter-10-advanced-functions.txt:294(搜「function_a」) · text/19-ch10-chapter-10-advanced-functions.txt:302(搜「Output: None」)
递归练习四题 同上 text/19-ch10-chapter-10-advanced-functions.txt:309(搜「def fib」) · text/19-ch10-chapter-10-advanced-functions.txt:319(搜「def digits」) · text/19-ch10-chapter-10-advanced-functions.txt:334(搜「def palindrome」) · text/19-ch10-chapter-10-advanced-functions.txt:357(搜「def count_ways」)
GenAI 互动区(递归深度等) 同上 text/19-ch10-chapter-10-advanced-functions.txt:389(搜「maximum recursion depth」)


  1. 出处:「CHAPTER 10: Advanced Functions」第 3–9 段(text/19-ch10-chapter-10-advanced-functions.txt:7,搜「nested, hierarchical, and recursive structures」)与第 392–405 段(text/19-ch10-chapter-10-advanced-functions.txt:395,搜「lists, tuples, sets, and dictionaries」)。三部分导读预告的四种数据结构即第 11–14 章。 ↩↩↩↩

  2. 出处:「CHAPTER 10: Advanced Functions」第 13–20 段(text/19-ch10-chapter-10-advanced-functions.txt:14,搜「output of one function is immediately used」;:16,搜「reduce the need for」)。三条收益逐字依据原文。 ↩↩↩

  3. 出处:「CHAPTER 10: Advanced Functions」第 22–52 段(text/19-ch10-chapter-10-advanced-functions.txt:23,搜「print(input('Enter your name」;:32,搜「abs(round(-4.567))」;:48,搜「len(str(12345))」)。四例及其输出(5、'Hello, there!'、5)逐字依据原文。 ↩↩

  4. 出处:「CHAPTER 10: Advanced Functions」第 38–47 段(text/19-ch10-chapter-10-advanced-functions.txt:39,搜「strip().capitalize().replace」;:42,搜「Hello, there!」)。方法链的三环与输出逐字依据原文。 ↩

  5. 出处:「CHAPTER 10: Advanced Functions」第 54–98 段(text/19-ch10-chapter-10-advanced-functions.txt:83,搜「def arithmetic」;:95–:98,四行算式输出)。六函数接力与输入 2、3 的输出逐字依据原文。 ↩

  6. 出处:「CHAPTER 10: Advanced Functions」第 100–153 段(text/19-ch10-chapter-10-advanced-functions.txt:135,搜「def avg(x, y, z)」;:150–:153,输入 1、2、3 及一行统计输出)。avg 套 total 的嵌套与完整输出见原文。 ↩

  7. 出处:「CHAPTER 10: Advanced Functions」第 155–162 段(text/19-ch10-chapter-10-advanced-functions.txt:158,搜「breaking down a large task」;:160,搜「readability, maintainability, and modularity」)。 ↩↩↩

  8. 出处:「CHAPTER 10: Advanced Functions」第 164–242 段(text/19-ch10-chapter-10-advanced-functions.txt:169,搜「def calculate_average」;:174,搜「def assign_letter_grade」;:189,搜「def print_results」;:193,搜「def process_single_student」;:210,搜「def process_student_grades」;:222–:233,Alice/Bob 两轮运行输出)。五函数结构、运行演示与分层讲解逐字依据原文。 ↩↩↩

  9. 出处:「CHAPTER 10: Advanced Functions」第 270–280 段(text/19-ch10-chapter-10-advanced-functions.txt:271,搜「a function calls itself」;:277,搜「The base case」;:279,搜「recursive case」)。递归定义与两零件逐字依据原文;俄罗斯套娃的类比是我们加的。 ↩↩↩

  10. 出处:「CHAPTER 10: Advanced Functions」第 283–291 段(text/19-ch10-chapter-10-advanced-functions.txt:284,搜「def factorial(n)」;:285,搜「n == 0 or n == 1」;:290,搜「factorial(5)」)。代码与输出 120 逐字依据原文;五层展开与回卷的逐步推演是我们补的验算。 ↩↩

  11. 出处:「CHAPTER 10: Advanced Functions」第 292–304 段(text/19-ch10-chapter-10-advanced-functions.txt:294,搜「def function_a」;:302,搜「Output: None」)。间接递归示例与 None 输出逐字依据原文;None 成因的解释依据第 09 章「无 return 返回 None」的机制。 ↩↩↩↩

  12. 出处:「CHAPTER 10: Advanced Functions」第 306–367 段(text/19-ch10-chapter-10-advanced-functions.txt:309,搜「def fib(n)」;:319,搜「def digits(n)」;:334,搜「def palindrome(s)」;:357,搜「def count_ways(n)」;:366,搜「count_ways(4)」)。四题代码、回文三测输出(True/False/True)与 count_ways(4)=5 逐字依据原文;「三种缩小刀」的归纳是我们的提炼。 ↩↩↩↩

  13. 出处:「CHAPTER 10: Advanced Functions」第 369–390 段(text/19-ch10-chapter-10-advanced-functions.txt:389,搜「maximum recursion depth」)。递归深度之问出自 GenAI 互动区,正文未答;深度默认值(约 1000 层)与 RecursionError 是通用知识补充。 ↩↩↩

  14. 出处:「CHAPTER 10: Advanced Functions」第 306–315 段(text/19-ch10-chapter-10-advanced-functions.txt:309,搜「def fib(n)」;:313,搜「fib(n - 1) + fib(n - 2)」)。fib 定义与两次自调结构逐字依据原文;递归树的完整展开与重复计数的观察是我们的推演。 ↩

  15. 出处:「CHAPTER 10: Advanced Functions」第 371–373 段(text/19-ch10-chapter-10-advanced-functions.txt:373,搜「How does it differ from an」)。迭代与递归之问出自 GenAI 互动区,正文未答,我们的回答即本节。 ↩↩

  16. 出处:「CHAPTER 10: Advanced Functions」第 73–76 段(text/19-ch10-chapter-10-advanced-functions.txt:73,搜「def substract」)。双 s 拼写见原文;「错得一致所以能跑」的观察是我们的分析。 ↩