📄 一句话概括
五个动作——推导式、不改入参、抽纯函数、用 map/key、可变默认参数改 None;5 个全部当场验证通过、0 个需要改架构——这就是【掌握】的意思:不用重写。
📝 本节和前面几节的关系
A.14 说完分工,这一节收尾:不讲理论,讲今天就能动的五件事。
一、实测五个动作
① 用推导式替 append:3 条语句 → 1 条。 ② 不改传入对象:返回新列表,原列表长度仍是 3。 ③ 抽纯函数:同输入 20 次只有 1 种结果。 ④ 用 map/key 代替手写循环:结果与手写版一致。 ⑤ 可变默认参数改 None:坏版两次共用同一列表,好版各自独立。 5 个全过,0 个需要改架构。
二、第 5 条为什么单列
def f(x, acc=[]) 里的 [] 只在定义时造一次,之后每次调用共用。
所以两次调用会累加到同一个列表——这是 Python 里最经典的一坑。
改法固定:acc=None,函数里再 acc = [] if acc is None else acc。
三、这一章该带走什么
不是【改用函数式】,是三样东西:推导式、纯函数、不改别人的东西。 这三样在面向对象的代码里同样能用,而且立刻能减少一批莫名其妙的 bug。 所以附章的落点和全书一样:你写的东西,别人改得动吗。
四、动手 Demo:掌握函数式编程
五个动作各写一版坏写法、一版好写法。 逐个验证过没过。
out1 = []
for i in range(3):
out1.append(i * 2)
out2 = [i * 2 for i in range(3)]
src = [1, 2, 3]
new = src + [4] # 不改入参
def pure(x):
return x + 1
same = len({pure(7) for _ in range(20)}) == 1
def bad(x, acc=[]):
acc.append(x)
return acc
def good(x, acc=None):
acc = [] if acc is None else acc
acc.append(x)
return acc
print(out1 == out2, len(src), same) # True 3 True
print(bad(1) == bad(2), good(1) != good(2)) # True True
实跑输出:
--------------------------------------------------------------------
掌握函数式编程
--------------------------------------------------------------------
从今天就能用的 5 个动作,**每个都能一行验一遍:**
动作 验证 过
---------------------------------------------------------------------------------
1 用推导式替 append 3 条 → 1 条语句 True
2 不改传入对象 原列表长度仍是 3 True
3 抽纯函数 同输入 20 次只有 1 种结果 True
4 用 map/key 代替手写循环 ['BB', 'A', 'CCC'] 对 ['BB', 'A', 'CCC'] True
5 可变默认参数改 None 坏版共用 = True,好版独立 = True True
五个动作 5 个
当场验证通过 5 个
需要改架构才能做的 0 个
**5 个动作全部可以在现有代码里立刻做**——**这才是【掌握】的意思:不用重写。**
**注意第 5 条**:`acc=[]` 是可变默认参数,**两次调用共用同一个列表**,这是最经典的一坑。
**所以函数式的第一课不是抽象,是【别偷偷改别人的东西】。**
实测:五个动作全部通过,0 个需要改架构。
第 5 条是最经典的一坑:acc=[] 只在定义时造一次,两次调用共用。
这一章要带走的就三样:推导式、纯函数、不改别人的东西。
30 秒实验
- 今天就在自己的代码里找一处
acc=[]或dict={}的默认参数,改成 None。 - 挑一个函数,把里面的 append 循环改成推导式。
常见误区
- 以为掌握函数式要学完单子。三样东西就够开工。
- 以为这是【另一种编程方式】。它是一组能塞进任何语言的习惯。
自测三问(点开对答案)
1. 五个动作是哪五个? —— 推导式替 append、不改入参、抽纯函数、用 map/key、可变默认参数改 None。 2. 为什么 acc=[] 是坑? —— 默认值只在定义时造一次,之后每次调用共用同一个列表。 3. 这一章要带走哪三样? —— 推导式、纯函数、不改别人的东西。- ☐ COLUMN 当今的OOP 打造了函数式语言的箱庭的Java(附章最后一篇)
相关笔记
- 函数式语言和面向对象的关系 — 上一条
- 特征5:没有副作用 — 第 2、3 条动作的根据
- 享受需要动脑的软件开发 — 全书判定标准
- 🧩 面向对象是怎样工作的 · 索引