🧩 第六章 重用:OOP带来的软件重用和思想重用
📄 一句话概括

所有类的继承链末端都是同一个祖先——一个空类一行代码没写,白拿了 29 个名字。

📝 本节和前面几节的关系

6.3 说标准库可靠,这一节说为什么不同来源的类能凑在一起用。

一、一个共同的祖先

实测 Leaf → Mid → Plain → object——再往上没有了。 所有类都自动继承 Object,不用你写。 这就是为什么【所有对象都像对象】:都能打印、都能比较、都能放进字典当键。

二、白拿了什么

实测空类 dir() 出来 29 个名字,全部继承自 object。 其中特殊方法 24 个:__str__、__eq__、__hash__、__repr__… 实测三件事都能跑:str(x) 有长度(类名+地址)、x == y 返回 False、hash(x) 有值。 一行代码没写,白拿 29 个名字。

三、这保证了互操作

类库之间不需要认识对方,只要都遵守 Object 的规矩。 json 能把任何对象塞进列表,collections 的容器能装任何对象——因为它们都【像对象】。 没有这个共同祖先,每个库都得为别人的类型写一遍适配。

四、该重写哪几个

__repr__:默认只给类名和地址,重写之后打印有内容(第五章那个 dump 的苦就靠它缓解)。 __eq__:默认比身份,两个内容相同的对象也判不等。 注意配套:重写 __eq__ 通常要一起重写 __hash__,否则对象不能当字典键。

五、动手 Demo:将 Object 类作为祖先类的继承结构

看一条三层继承链的末端是什么。 再数一数一个空类到底白拿了多少名字。

class Plain: pass
class Mid(Plain): pass
class Leaf(Mid): pass

print([c.__name__ for c in Leaf.__mro__])
print(len(dir(Plain)))              # 白拿了多少
print(len(str(Plain())))            # 照样能打印
print(hash(Plain()) is not None)    # 照样能哈希

实跑输出:

--------------------------------------------------------------------
将 Object 类作为祖先类的继承结构
--------------------------------------------------------------------

  所有类的继承链末端都是同一个祖先——**Object**。实测:

      Leaf 的继承链                Leaf → Mid → Plain → object
      祖先类名字                   object
      Object 提供的公开方法        0 个
      Object 提供的特殊方法        24 个(__str__/__eq__/__hash__ 等)
      空类一共继承了多少名字       29 个

      一个空类照样能用:
        str(Plain()) 的长度        55 个字符(类名+地址)
        Plain() == Plain()         False
        hash(Plain()) 存在吗       True

  **一行代码没写,白拿了 29 个名字。**这就是祖先类的价值。
  **它保证了【所有对象都像对象】**:都能打印、都能比较、都能放进字典当键。
  **所以类库之间可以互操作**——它们不需要认识对方,只要都遵守 Object 的规矩。

实测:继承链是 Leaf → Mid → Plain → object,空类白拿了 29 个名字。 所有对象都像对象——类库之间不需要认识对方,只要都遵守 Object 的规矩就能互操作。

30 秒实验

  1. 打印 类型.__mro__,确认你写的类末端也是 object。
  2. 给你的类重写 __repr__,对比重写前后打印的差别。

常见误区

  1. 以为 object 是个可选的父类。它是所有类的默认祖先。
  2. 以为重写 eq 就够了。通常要连 hash 一起改。
自测三问(点开对答案) 1. 所有类的祖先是谁?实测继承链是什么? —— object;实测 Leaf → Mid → Plain → object,末端就是它。 2. 一个空类白拿了多少名字? —— 29 个(其中特殊方法 24 个),所以空类也能打印、比较、哈希。 3. 这个共同祖先保证了什么? —— 互操作:不同来源的类不需要认识对方,只要都像对象,就能塞进同一个容器、被同一个库处理。

相关笔记