函数与方法 — 参数的艺术、递归与树¶
这一章讲函数:定义它、喂参数给它、让它返回值。 但原书的重心不在语法,而在三件「分寸」: 函数写多短、参数放几个、什么时候该用递归。读完你会理解作者的标尺—— 函数短到一眼能懂;参数少到一眼能数;递归只留给「结构本身是递归的」问题。
1. 这一章讲什么¶
原书开场的观察:Python 代码里只要看到圆括号 (),大概率是函数在起作用——
split、enumerate、range、append,前面章节用过的都是。1
先消一个术语:函数(function)与方法(method)的差别只有一个——方法定义在类里面、隐含作用在类的一个实例上;除此之外两者几乎相同。 作者明说他在本章混用这两个词。2
本章地图:
定义(def、缩进、return) → 参数的三种增强(关键字、默认值、*args/**kwargs)
→ 命令行参数(sys.argv) → 定义顺序与循环依赖
→ 递归(阶乘 → 凑硬币) → 树(递归数据结构的标准战场)
图说:前三块讲「函数的形」,后两块讲「函数的魂」。
2. 核心原理一:定义与调用契约¶
解决什么问题: 把一段逻辑包起来,起个名字,随处复用。
怎么做(主线例子): 最小函数和它的契约:
def add(a, b): # def + 名字 + (参数) + 冒号;函数体靠缩进(没有大括号!)
return a + b
add(3, 4) # 7
add(3) # TypeError: add() missing 1 required positional argument: 'b'
两个细节是 Python 特色:函数体用缩进而非大括号界定(缩进是语法的一部分,不是风格);
调用时参数个数必须匹配,多了少了都立刻报 TypeError,报错信息直接告诉你缺了谁。3
长度规矩: 函数要尽可能短——短到一行都可以;到了 20 行左右就该警惕:「那种长度的函数极难理解。」 最终裁决权在你:问自己「它还算一眼能懂吗」。4 这与第 02 章一脉相承:名字难起(太长)是函数该拆的信号。
3. 核心原理二:参数传递的三种增强¶
3.1 关键字参数:把「位置」换成「名字」¶
解决什么问题: 位置参数要求调用者记住顺序;参数多了,f("anna", 2) 里的 2 是什么?
怎么做: 传参时连名带值:print_name_n_times(name="mike", n=1)。
两个红利:顺序随意(n=1, name="mike" 也行)、自解释(调用处直接可读)。5
混用的规矩:关键字参数后面的参数必须也是关键字(f(n=2, "anna") 直接 SyntaxError)——
「位置参数不能跟在关键字参数后面」。5
参数个数的上限(作者的硬规矩): 大约三个;超过五个,「就该认真重想你的代码了」。 办法在下一章——把一组相关参数装进一个对象(类)里,一个参数顶五个。6
魔法数字(magic numbers): 参数列表里凭空冒出来的数,叫魔法数字——读代码的人只看到值、看不到名字, 「像坏的魔法」。解法和变量命名同构:给数起个名字再传。7
3.2 默认参数:给「通常如此」的值一个家¶
解决什么问题: 多数调用都用同一个值,少数调用才换。
怎么做:
def power(x, exponent=2): # 指数默认 2
return x**exponent
power(3) # 9 —— 不传就用默认
power(3, 3) # 27
power(x=3, exponent=3) # 关键字照常可用
语法红线同 3.1:带默认值的参数后面不能跟不带默认值的参数(def f(a=1, b) 非法)。8
为什么有效: 默认参数把「最常见的用法」写成最短的形态,调用处不再被惯常值淹没; 边界:默认值的「常用」会变——需求变了记得改默认,不然调用处都跟着错。
3.3 *args 与 **kwargs:收「任意多个」的口袋¶
解决什么问题: 有时参数个数真的无法预先确定——典型场景:包装器(wrapper,包在别的函数外面加一层逻辑的函数), 它得把收到的任何参数原样转交给被包的函数。
怎么做:
def dealing_with_args(*args, **kwargs):
for arg in args: # args 是「位置参数的元组」
print(arg)
for key, value in kwargs.items(): # kwargs 是「关键字参数的字典」
print(f"{key}: {value}")
dealing_with_args(1, 2, a=3, b=4) # 1 / 2 / a: 3 / b: 4
*args 把多余的位置参数收成 tuple,**kwargs 把多余的关键字参数收成 dict。
wrapper 的标准形态:def wrapper(*args, **kwargs): ...; add(*args, **kwargs); ...——
进来的参数一分不少地转交出去。9
作者的保留意见: 别像示例里那样随手用 *args。「如果 args 里所有元素地位相等,改用 list 更诚实——
你的意图一目了然。」args 的正当主场就是 wrapper 这类「透明转发」。9
3.4 命令行参数:sys.argv 与配置文件的边界¶
C/C++ 的 main 函数收参数;Python 里没有这个待遇——命令行参数要从 sys 模块的 argv 列表里拿,
且第一个元素是脚本自己的名字:
作者的边界感一如既往:参数少,用命令行参数;参数多,「该用配置文件」——别整一串命令行旗标折磨用户。10
3.5 关键字参数的完整对照实验¶
书里把关键字参数的玩法给全了,逐条对账:5
def print_name_n_times(name, n):
for _ in range(n):
print(name)
# 位置版:顺序必须和定义一致
print_name_n_times("anna", 2) # anna / anna
# 关键字版:顺序随意
print_name_n_times(name="mike", n=1) # mike
print_name_n_times(n=1, name="mike") # mike —— 顺序换了,结果一样
# 混合版:不带关键字的排前面,带关键字的排后面
print_name_n_times("anna", n=2) # anna / anna ✓
# 非法版:关键字在前、位置在后
print_name_n_times(n=2, "anna") # SyntaxError: positional argument follows keyword argument
第四条为什么非法?位置参数 "anna" 不知道该往哪塞——它只能匹配第一个空位 name,
但 name 已经被关键字 n=2 的邻居们打乱了座次。Python 干脆禁掉这个含糊形状,
逼你在调用处把话说全。报错的那行原话值得看一眼:「positional argument follows keyword argument」——
报错信息本身就是语法课。5
书里还有一个常被跳过的等价关系:关键字参数 ≈ 先把值放进变量再传:
print_name_n_times(name="anna", n=2) # 关键字直传
name = "anna"; n = 2
print_name_n_times(name, n) # 变量代传:效果相同,但绑定顺序
「效果相同」但不完全等价:变量版受位置约束,关键字版不受。作者列这段的目的是说明 关键字参数没有引入新能力,只是把「顺序约束」变成了可选项——代价是调用处略啰嗦。5
4. 核心原理三:定义顺序、循环依赖与控制流¶
4.1 顺序无所谓,但「调用先于定义」不行¶
Python 在执行整个文件之前先读整个文件,所以函数的定义顺序无所谓——
a 里调用 b,b 写在 a 后面也照样工作。但「在定义之前调用」是 NameError。11
作者的个人偏好(不是规则):从最内层的函数开始写,减少「还没定义就被引用」的心智负担; 如果因此文件难读,说明该把源文件拆成多个小文件再 import 了——拆文件是第 13 章的主题。11
4.2 函数的循环依赖¶
a 调 b、b 调 a——书里连运行都不运行(会永远跑下去),直接定性:
「无论如何要避免循环依赖。它是你还没理解问题的逻辑的信号。」12
这与第 07 章对象级的循环依赖禁令是同一条,只是发生在函数层。
4.3 控制流:定义不等于执行¶
新手常踩的坑:以为函数定义后会立刻运行。书里演示:
历史注脚:很久以前代码靠 goto(跳转到任意行的语句)从上往下流,极易出错;
函数和循环接管了控制流之后,「那些日子过去了」。13
5. 核心原理四:递归——函数调用自己¶
5.1 最小例子:阶乘¶
解决什么问题: 一类问题的定义本身就引用自己——「n 的阶乘 = n × (n−1) 的阶乘」。
怎么做(主线例子):
def factorial(n):
if n == 0:
return 1 # 基准情形:递归到此为止
return n * factorial(n - 1) # 自己调用自己,问题规模 −1
factorial(5) # 120
走一遍 n=3:factorial(3) → 3 × factorial(2) → 2 × factorial(1) → 1 × factorial(0) → 1;
层层返回:1 × 1 × 2 × 3 = 6。基准情形(base case)是递归的刹车——没有它,函数无限自我调用,栈耗尽报错。14
作者的态度克制:循环版阶乘同样几行,「存在递归解,不代表递归总是最优」。 他的潜台词在下一节——递归的正当舞台是树。14
5.2 凑硬币:递归搜索¶
一个更立体的例子:用面额 [10, 5, 2, 1] 凑出 15,有多少种组合?递归解法的结构:
对每个可用面额,递归「凑剩下的钱」,amount 归零时打印这一路用过的硬币。
书里特意提醒:硬币用了整数——若用浮点(如 0.2 欧元),== 和 <= 会因舍入出错(第 03 章的老朋友)。15
5.3 树:递归的主场¶
解决什么问题: 数据本身是层层包含的——一个节点装着几个子节点,子节点又装子节点。 这就是树(tree):节点(node)装子节点(children);最顶是根节点(root),不含子节点的是叶节点(leaf)。16
怎么做: 用类实现节点(这是第 11 章的预习):
class Node:
def __init__(self, value):
self.value = value
self.children = []
def add_child(self, child):
self.children.append(child)
root = Node(1)
child1 = Node(2); root.add_child(child1)
child2 = Node(3); root.add_child(child2)
对这棵树求所有值的和,递归一行是一层结构:
def sum_tree(node):
sum = node.value
for child in node.children:
sum += sum_tree(child) # 对每个子节点,做「同样的事」
return sum
sum_tree(root) # 6 = 1 + 2 + 3
走一遍:root 的值 1,加上对 child1 递归(返回 2)、对 child2 递归(返回 3),得 6。 为什么这里递归无可替代: 树的定义是递归的(节点包含节点),遍历它自然也递归—— 换成循环你得自己维护「待访问列表」,代码更长、更险。书里的话:「遇到递归数据结构的问题,就用树; 对树工作,总是用递归。」16
sum_tree 的执行,再展开成调用栈看(树的形状见原书图 6.1:1 是根,2、3 是叶):
sum_tree(root=1): sum = 1
├─ sum_tree(child=2): 没有孩子 → 返回 2 ← 叶节点的递归,一进就回
├─ 累加:sum = 1 + 2 = 3
├─ sum_tree(child=3): 没有孩子 → 返回 3
└─ 累加:sum = 3 + 3 = 6 → 返回 6
注意一个心智转换:对列表用循环(扁平),对树用递归(嵌套)。 判断标准就一条:数据是平的还是套的。套的用递归,不是炫技,是语法的形状和数据的形状一致。16
5.4 函数重载的 C++ 对照,完整读¶
书里用 C++ 讲清了 Python 缺什么、怎么补。对照代码:17
void f(int x) { cout << "int"; } // 接受整数的版本
void f(double x) { cout << "double"; } // 接受浮点的版本
f(3); // 打印 int —— 编译器看参数类型,选第一个
f(3.0); // 打印 double —— 选第二个
重载(overloading)= 同名函数、按参数类型分流,编译器替你选。 Python 没有编译器,同名函数后者覆盖前者——所以书里给的替代是「分发函数」:
def f_int(): print("int")
def f_float(): print("float")
def f(x):
if type(x) == int: f_int()
elif type(x) == float: f_float()
f(3) # int
f(3.0) # float
作者的评价:「不如重载优雅,但能用。」17 这个对照的教学价值不在「Python 缺了功能」, 而在让你看清重载的本质——它是编译期把类型检查变成选择器; Python 把同一件事挪到了运行期(type() 判断),还附带一句大实话: 这种分发本身,正是第 08 章想让你用多态消灭的 if 链。 三层的关联在这里合拢:重载 → 分发 if → 多态,是同一条路的三个时代。
5.2 递归的完整展开:factorial(3) 的六帧栈¶
递归常被讲成「函数调用自己」一句话就带过,那样学不会。把它展开成调用栈(程序内部记住「谁调了谁」的那叠便签)看:14
调用 factorial(3)
3 ≠ 0 → 要 3 × factorial(2),先算 factorial(2)
2 ≠ 0 → 要 2 × factorial(1),先算 factorial(1)
1 ≠ 0 → 要 1 × factorial(0),先算 factorial(0)
0 == 0 → 返回 1 ← 基准情形,下山的起点
1 × 1 = 1,返回 1
2 × 1 = 2,返回 2
3 × 2 = 6,返回 6 ← 栈清空,答案是 6
每一层「先算完再乘」——递归的深度 = 嵌套的层数,层数由「问题缩小得多快」决定: 每次 n−1,深度就是 n 层。两件事必须同时成立,递归才安全: 1. 问题每步缩小(否则原地打转,无限递归); 2. 存在一个直接返回的基准情形(否则缩到底也没答案)。 factorial 两条都满足:n 单调下降,0 直接返回。14
5.3 凑硬币:递归搜索的完整一步¶
凑硬币例子(面额 10、5、2、1,凑 15)的递归一步,拆开看:15
coins_available = [10, 5, 2, 1]
def get_coins(amount, coins_used, max_value):
if amount == 0:
print(coins_used) # 凑齐了,打印这一路
for coin_value in coins_available:
if coin_value <= amount and coin_value <= max_value:
get_coins(amount - coin_value, # 剩余金额
coins_used + [coin_value], # 记上这一枚
coin_value) # 保证不重复使用更大的(防重复计数)
get_coins(amount=15, coins_used=[], max_value=coins_available[0])
# 打印 [10, 5],以及 [5, 5, 5]、[10, 2, 2, 1] 等全部组合
三个参数的分工:amount 是还要凑多少,coins_used 是已经凑了哪些,max_value 是防回头 (避免 [10, 5] 和 [5, 10] 算两遍)。递归在这里做的事,本质是对一棵「选择树」做深度优先遍历: 每个分叉是「下一枚选哪个面额」,叶子是「amount 归零」。树的遍历,正是下一节的主角。15
书里还给了非递归版阶乘(循环累乘),评价克制:「存在递归解不代表递归总是最优;这个 case 用哪个,你自己定。」 ——递归是工具不是风格,它真正的不可替代性在下节的树。14
6. 作者的判断与证据¶
书里给了证据的: 全部示例可直接运行;TypeError/SyntaxError/NameError 的报错原文给出;
凑硬币、树求和是完整可复现的演示。31516
作者的判断(立场与经验):
- 「函数 ≤ 20 行、参数 ≤ 3 个」——他的标尺,比多数风格指南严;作为默认值好,作为法律则会在数据管道类代码里频繁误伤;
- 「函数重载缺失不是损失」——Python 社区共识:用多态(第 12 章)或单函数内分派替代;书里给的
type(x) == int分派是最朴素的版本; - 「递归只留给树」——保守而安全的教学立场。
判断(我们的,不是书里的): 「参数 ≤ 3」真正要防的不是数字,是参数的异质性: 三个互不相关的参数是 3 种心智负担,一个打包了三个相关字段的对象是 1 种。 所以这条规矩的现代化说法是「参数应该是同级的、少量的概念单位」——5 个同级的标量参数(一个个单独的数,没有打包), 确实不如一个配置对象;但 3 个各自承载独立维度的参数,并不比 1 个对象差。 如果错,会错在: 过度打包会把「调用处需要构造对象」的成本转嫁回来,小脚本里反而啰嗦; 作者的标尺在小项目里更适用,我们的修订在大项目里更适用。
6.1 函数一章的完整主线,回放¶
定义(def、缩进、return)── 调用契约(个数、类型迟查)
├─ 参数增强:关键字(顺序随意)→ 默认值(惯常值隐身)→ *args/**kwargs(透明转发)
├─ 命令行:sys.argv(第 0 项是脚本名)
├─ 顺序:定义先后无所谓,调用先于定义不行;循环依赖 = 没想清问题
└─ 递归:基准情形 + 问题缩小;树是它的主场
图说:六块拼成「函数的完整形状」;中间的标尺始终是「读者一眼能不能懂」。
这张回放图也是本章的自测题:遮住每一行的解释,能复述那一行在防什么错, 说明函数这一章读透了;复述不出的,回到对应小节——每节都有一条书里给过的报错信息, 报错是最好的复习材料。3
7. 边界与局限¶
- 函数重载只有 C++ 对照,Python 的
functools.singledispatch(官方的分派方案)没提; - 匿名函数
lambda没出现; - 装饰器只作为
*args的用例露了一面(第 14 章还有一次计时装饰器的实战); - 递归没讲栈深度限制(Python 默认递归约 1000 层,深递归会
RecursionError)——树很深时这是真问题; - 凑硬币例子没讲「记忆化」——递归搜索的重叠子问题会按指数级(规模每大一档、计算量翻几倍)重复计算,这是它「笨拙」的代价。
7.1 默认参数的一个暗坑,书里没提但迟早会踩¶
默认值在定义时求值,且整个函数共用同一个对象——这在可变默认值上是著名陷阱:
def append_to(item, target=[]): # 危险:这个 [] 只创建一次!
target.append(item)
return target
append_to(1) # [1]
append_to(2) # [1, 2] —— 不是 [2]!上一次的列表还在
书里没有讲这个坑(它的示例都是数字默认值,无此问题),但「默认参数在定义时求值」 是语言机制,不属于风格之争;对策也简单:默认值用 None,函数体里再换真正的空对象。 记住这个坑和它的对策,比记住「默认参数很方便」重要一倍。8
这个坑也顺带解释了书里 get_sum_of_file(file_name, data_provider=get_content) 为什么安全:
函数默认值,函数对象创建一次,但 get_content 是函数引用——引用本身不可变,
每次调用拿到的都是同一个「读文件的函数」,没有副作用可积累。陷阱只在默认值是可变对象
(列表、dict)时出现;默认值是函数或数字时永远安全——判断口诀只有一句:默认值会不会被调用者共享后修改——会,就用 None 占位——这是 Python 社区对这个坑的标准答案,也是面试高频题——值得现在就记下来,免得将来在凌晨三点的报错里重新学一遍——报错是最好的老师,但也是最贵的那一种——学费是睡眠,教材是事故现场——所以趁现在,把坑都预习掉——这一节的坑,就是预习的第一站;预习完,才算真正会用默认参数——而不是被默认参数用——工具和人,总有一个在驾驭。
8. 可带走的¶
本章主线例子,一行写完: factorial(3) → 3×factorial(2) → 2×factorial(1) → 1×factorial(0)=1,
层层返回 6;刹车是基准情形 n == 0。14
- 函数体靠缩进;参数个数错了,TypeError 的报错会直接告诉你缺谁。
- 函数短到一眼懂;20 行该警惕;名字太长是拆的信号。
- 参数 ≤ 3 个;超过 5 个,装进对象。 魔法数字先起名再传。
- 关键字参数让调用处自解释、顺序随意;默认参数藏起惯常值;位置参数永远跟在关键字后。
*args/**kwargs留给「透明转发」的 wrapper;元素地位相等的参数用 list 更诚实。- 命令行参数用 sys.argv(第 0 项是脚本名);参数多了用配置文件。
- 定义顺序无所谓,调用先于定义不行;循环依赖 = 没想清楚问题。
- 递归 = 结构递归时的自然写法(树、阶乘);基准情形是刹车;浮点上别用递归判等。
- Python 没有函数重载——同名函数后者覆盖前者;替代是多态或函数内分派。
- 数据是平的用循环,套的用递归——语法的形状和数据的形状保持一致。
- 递归安全两条:问题每步缩小 + 基准情形直接返回;缺一条就是栈溢出预定了。
- 报错信息是最好的复习材料:每个语法红线都配了原话,卡住时先读报错。
9. 原文地图¶
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| 函数无处不在、与方法的关系 | 6 Functions and Methods | text/22-ch06-6-functions-and-methods.txt:3(搜「round brackets」) · text/22-ch06-6-functions-and-methods.txt:8(搜「Functions vs. Methods」) |
| def、缩进、参数个数报错 | 6 Functions and Methods | text/22-ch06-6-functions-and-methods.txt:33(搜「def keyword」) · text/22-ch06-6-functions-and-methods.txt:50(搜「missing 1 required」) |
| 函数长度规矩 | 6 Functions and Methods | text/22-ch06-6-functions-and-methods.txt:25(搜「20 lines」) |
| 关键字参数与顺序规则 | 6 Functions and Methods | text/22-ch06-6-functions-and-methods.txt:55(搜「Keyword Arguments」) · text/22-ch06-6-functions-and-methods.txt:92(搜「positional argument follows」) |
| 参数三五个上限 | 6 Functions and Methods | text/22-ch06-6-functions-and-methods.txt:111(搜「three arguments」) |
| 魔法数字 | 6 Functions and Methods | text/22-ch06-6-functions-and-methods.txt:115(搜「out of nowhere」) |
| 默认参数 | 6 Functions and Methods | text/22-ch06-6-functions-and-methods.txt:121(搜「Default Arguments」) |
| args/kwargs、wrapper | 6 Functions and Methods | text/22-ch06-6-functions-and-methods.txt:146(搜「arbitrary number」) · text/22-ch06-6-functions-and-methods.txt:165(搜「wrapper」) |
| sys.argv | 6 Functions and Methods | text/22-ch06-6-functions-and-methods.txt:181(搜「sys.argv」) |
| 函数重载的 C++ 对照与分派替代 | 6 Functions and Methods | text/22-ch06-6-functions-and-methods.txt:200(搜「Function Overloading」) · text/22-ch06-6-functions-and-methods.txt:224(搜「not as elegant」) |
| 控制流:定义不等于执行、goto 历史 | 6 Functions and Methods | text/22-ch06-6-functions-and-methods.txt:241(搜「Control Flow」) |
| 定义顺序、调用先于定义 | 6 Functions and Methods | text/22-ch06-6-functions-and-methods.txt:260(搜「doesn’t matter」) · text/22-ch06-6-functions-and-methods.txt:276(搜「NameError」) |
| 函数的循环依赖 | 6 Functions and Methods | text/22-ch06-6-functions-and-methods.txt:290(搜「Cyclic Dependencies」) |
| 递归与阶乘、基准情形 | 6 Functions and Methods | text/22-ch06-6-functions-and-methods.txt:306(搜「calls itself」) · text/22-ch06-6-functions-and-methods.txt:310(搜「factorial」) |
| 凑硬币与浮点告诫 | 6 Functions and Methods | text/22-ch06-6-functions-and-methods.txt:335(搜「coins」) · text/22-ch06-6-functions-and-methods.txt:357(搜「rounding errors」) |
| 树的定义与递归求和 | 6 Functions and Methods | text/22-ch06-6-functions-and-methods.txt:365(搜「called the root」) · text/22-ch06-6-functions-and-methods.txt:387(搜「sum_tree」) |
-
出处:「6 Functions and Methods」第 3–6 段(
text/22-ch06-6-functions-and-methods.txt:3,搜「round brackets」)。 ↩ -
出处:「6 Functions and Methods」第 8–12 段(
text/22-ch06-6-functions-and-methods.txt:8,搜「Functions vs. Methods」)。 ↩ -
出处:「6 Functions and Methods」第 33–53 段(
text/22-ch06-6-functions-and-methods.txt:35,搜「must be indented」;第 47 段,搜「missing 1 required positional argument」)。 ↩↩↩ -
出处:「6 Functions and Methods」第 23–27 段(
text/22-ch06-6-functions-and-methods.txt:25,搜「20 lines」)。 ↩ -
出处:「6 Functions and Methods」第 55–99 段(
text/22-ch06-6-functions-and-methods.txt:76,搜「any order」;第 90 段,搜「positional argument follows keyword argument」)。 ↩↩↩↩↩ -
出处:「6 Functions and Methods」第 108–112 段(
text/22-ch06-6-functions-and-methods.txt:111,搜「three arguments at most」)。 ↩ -
出处:「6 Functions and Methods」第 114–120 段(
text/22-ch06-6-functions-and-methods.txt:115,搜「out of nowhere」)。 ↩ -
出处:「6 Functions and Methods」第 121–142 段(
text/22-ch06-6-functions-and-methods.txt:129,搜「exponent=2」;第 138 段,搜「after arguments with a default」)。 ↩↩ -
出处:「6 Functions and Methods」第 144–179 段(
text/22-ch06-6-functions-and-methods.txt:146,搜「arbitrary number of arguments」;第 163 段,搜「wrapper」;「用 list 更诚实」见第 164 段,搜「considered equal」)。 ↩↩ -
出处:「6 Functions and Methods」第 180–198 段(
text/22-ch06-6-functions-and-methods.txt:181,搜「sys.argv」;「配置文件」见第 197 段,搜「configuration file」)。 ↩ -
出处:「6 Functions and Methods」第 258–288 段(
text/22-ch06-6-functions-and-methods.txt:261,搜「reads the whole file」;第 274 段,搜「NameError」)。 ↩↩ -
出处:「6 Functions and Methods」第 290–302 段(
text/22-ch06-6-functions-and-methods.txt:302,搜「sign that you haven’t understood」)。 ↩ -
出处:「6 Functions and Methods」第 241–256 段(
text/22-ch06-6-functions-and-methods.txt:244,搜「“World” is printed before “Hello”」;goto 历史见第 251 段,搜「goto statements」)。 ↩ -
出处:「6 Functions and Methods」第 304–328 段(
text/22-ch06-6-functions-and-methods.txt:310,搜「factorial」;「up to you」见第 328 段)。 ↩↩↩↩↩↩ -
出处:「6 Functions and Methods」第 335–358 段(
text/22-ch06-6-functions-and-methods.txt:338,搜「coins_available」;浮点告诫见第 355 段,搜「rounding errors」)。 ↩↩↩↩ -
出处:「6 Functions and Methods」第 360–393 段(
text/22-ch06-6-functions-and-methods.txt:365,搜「called the root」;第 386 段,搜「recursion」;求和代码见第 387 段,搜「sum_tree」)。 ↩↩↩↩ -
出处:「6 Functions and Methods」第 200–239 段(
text/22-ch06-6-functions-and-methods.txt:202,搜「Function Overloading」;「not as elegant」见第 223 段)。 ↩↩