📄 一句话概括
同一需求两版:类版 1 个可变状态、函数版 0 个,结果都是 378.0——面向对象管【谁】和【状态】,函数式管【怎么变】,真实系统两者并用。
📝 本节和前面几节的关系
A.13 说完课题,这一节回到全书主线:这两个范式不是对手,是分工。
一、实测:两版结果一样
类版:Cart 三个方法(add/total/init),可变状态 1 个(self.items)。 函数版:一个纯函数,可变状态 0 个,结果也是 378.0。 结果一致说明它不是【谁更强】的比赛。 类版多出来的是【谁在改它】——身份与责任。
二、分工在哪
面向对象管【谁】:这个购物车属于谁、谁能改它、改完通知谁。 函数式管【怎么变】:一份数据进来,算出另一份数据出去,中间不留痕。 所以两者能合起来用:对象持有状态,方法内部用纯函数做变换。 这也是今天主流语言的默认形态。
三、判断该用哪个
有身份、有生命周期、要记住上一步 → 对象。 只是把 A 变成 B、算完就完 → 纯函数。 判断依据一句话:这东西需要【记得住】吗? 需要就是对象。
四、动手 Demo:函数式语言和面向对象的关系
同一需求(购物车打折)写类版与函数版。 比较可变状态个数与结果。
class Cart:
def __init__(self):
self.items = []
def add(self, p):
self.items.append(p)
def total(self):
return sum(p for p in self.items if p > 100) * 0.9
def fp_total(items):
return sum(p for p in items if p > 100) * 0.9
c = Cart()
for p in [50, 120, 300]:
c.add(p)
print(c.total(), fp_total([50, 120, 300])) # 378.0 378.0
print(len(c.items)) # 3(对象记住了)
实跑输出:
--------------------------------------------------------------------
函数式语言和面向对象的关系
--------------------------------------------------------------------
同一需求(购物车打折算总价)两版,**量行数与可变状态个数:**
写法 结构 可变状态 结果
------------------------------------------------
类版 Cart 三个方法 1 378.0
函数版 一个纯函数 0 378.0
两版结果一致 True
类版可变状态 self.items(会被 add 改)
函数版可变状态 0 个(只读入参、返回新值)
类版多出来的东西 【谁】在改它(身份与责任)
**注意两版结果一样**——**这说明它不是【谁更强的比赛】,是分工。**
**面向对象管【谁】和【状态】**:这个购物车属于谁、谁能改它、改完通知谁。
**函数式管【怎么变】**:一份数据进来,算出另一份数据出去,中间不留痕。
**所以真实系统里两者并用**:**对象持有状态,方法内部用纯函数做变换。**
实测:类版 1 个可变状态、函数版 0 个,结果都是 378.0。 面向对象管【谁】和状态,函数式管【怎么变】。 真实系统的默认形态是两者并用:对象持状态,方法内部用纯函数做变换。
30 秒实验
- 挑一个你的类,把其中一个方法内部的循环改成推导式或纯函数。
- 判断这个类该不该保留——它需要【记得住】吗?
常见误区
- 把两个范式当对手。它们解决的是两个不同问题。
- 为了纯,把需要记住的状态也塞进参数里传来传去。那是自找麻烦。
自测三问(点开对答案)
1. 两版结果一样说明什么? —— 说明不是谁更强的比赛,而是分工:一个管状态,一个管变换。 2. 两者的分工怎么分? —— 面向对象管谁和状态,函数式管怎么变。 3. 判断用哪个的一句话? —— 这东西需要记得住吗?需要就是对象。- ☐ A.15 掌握函数式编程
相关笔记
- 函数式语言的课题 — 上一条
- 掌握函数式编程 — 怎么上手
- 将面向对象作为工具熟练掌握 — 同样的取舍逻辑
- 🧩 面向对象是怎样工作的 · 索引