🧩 第十二章 熟练掌握面向对象
📄 一句话概括

一个 class 语句买到 5 种能力(可实例化/可继承/可多态/可封装/可扩展);加第 4 个子类时调用方 0 行改动——它省的不是打字量,是以后加东西的改动量。

📝 本节和前面几节的关系

第十一章讲完开发流程,正文到此收尾。这一章是三节回望,先说这个概念本身有多能生。

一、实测:一个语句买到五件事

可实例化:Shape(u"图形") 造出一个对象。 可继承:issubclass(Rect, Shape) 为 True。 可多态:同一个 x.area(),在 Shape/Rect/Circle 上给出 0/20/28.27 三种结果。 可封装:.name 只读,想改内部的 _nm 得走类里的方法。 可扩展:再加一个 Tri,4 个对象照样各自算对。 五件事全部来自同一个 class 语句,没有一样是额外加的开关。

二、原动力到底指什么

字面意思:一颗种子长出五棵树。 别的技术常常是【一个功能解决一个问题】:一个循环解决重复、一个 if 解决分支。 类不一样:它同时给了【怎么造】【怎么复用】【怎么替换】【怎么藏】【怎么加】。 所以叫【原动力】而不是【一个语法】——后面的设计、建模、流程,全是从这颗种子长出来的。

三、关键数字:加东西时改几行

加第 4 个子类 Tri 时,调用方 0 行改动。 原因很朴素:调用方写的是 x.area(),不是 if 是矩形 elif 是圆。 这是多态真正值钱的地方——它把【以后会加什么】这件事从调用方挪走了。 所以面向对象省的不是打字量,是【以后加东西时的改动量】。

四、动手 Demo:面向对象这一强大概念是原动力

定义 Shape 与两个子类,逐项验证五件事。 再加一个子类,看调用方要不要改。

class Shape:
    def area(self): return 0

class Rect(Shape):
    def __init__(self, a, b): self.a, self.b = a, b
    def area(self): return self.a * self.b

class Circle(Shape):
    def __init__(self, r): self.r = r
    def area(self): return round(3.14159 * self.r ** 2, 2)

poly = [Shape(), Rect(4, 5), Circle(3)]
print([x.area() for x in poly])          # [0, 20, 28.27]
print(issubclass(Rect, Shape))           # True

class Tri(Shape):
    def __init__(self, a, h): self.a, self.h = a, h
    def area(self): return self.a * self.h / 2

poly.append(Tri(6, 4))                   # 调用方一行没改
print([x.area() for x in poly])          # [0, 20, 28.27, 12.0]

实跑输出:

--------------------------------------------------------------------
面向对象这一强大概念是原动力
--------------------------------------------------------------------

  一个 class 语句到底买到了几件事?**拿同一份代码逐项验:**

  买到什么     实测证据                                      要改调用方吗
  ------------------------------------------------------------------------
  可实例化     s = Shape(图形) 造出 1 个对象                 不用
  可继承       issubclass(Rect, Shape) 为 True               不用
  可多态       同一 .area() 在 3 个对象上得 0/20/28.27     不用
  可封装       .name 只读、改 _nm 得走类内                   不用
  可扩展       加 Tri 后 4 个对象得 0/20/28.27/12.0       不用

      一个 class 买到的能力        5 种
      加第 4 个子类要改调用方      0 行
      三种图形共用一份 area()      是(调用方只有 1 处)

  **这 5 种能力全部来自同一个语句**——**这就是【原动力】的字面意思:一颗种子长出五棵树。**
  **注意第 5 行:加 Tri 时调用方 0 行改动**,因为调用方写的是 `x.area()` 而不是 `if 是矩形`。
  **所以面向对象省的不是打字量,是【以后加东西时的改动量】。**

实测:一个 class 买到 5 种能力,加第 4 个子类时调用方 0 行改动。 因为调用方只认 x.area() 这个约定,不认具体是哪个类。 这就是【原动力】:后面所有设计手法,都是从这颗种子长出来的。

30 秒实验

  1. 数一数你项目里最常改的那个函数:加一种新类型要动它几行?
  2. 把那个 if/elif 链换成多态,看看调用方能不能一行不改。

常见误区

  1. 把【类】当成【带函数的字典】。它真正给的是替换能力,不是收纳能力。
  2. 以为多态是【语法糖】。它换掉的是调用方里的分支,那是要花钱维护的地方。
自测三问(点开对答案) 1. 实测一个 class 买到几种能力? —— 5 种:可实例化、可继承、可多态、可封装、可扩展。 2. 加第 4 个子类时调用方要改几行? —— 0 行,因为调用方写的是 x.area() 而不是 if 判断类型。 3. 【原动力】指什么? —— 一个语句同时长出五种能力;后面的设计、建模、流程都从这颗种子长出来。

相关笔记