🧩 第四章 面向对象编程技术:去除冗余、进行整理
📄 一句话概括

包给名字划地盘——实测两个同名 Util 类,名字一模一样,类是两个。

📝 本节和前面几节的关系

4.14 说三个结构都管边界,这一节讲第一条:命名边界。

一、它解决两个问题

命名撞车:两个团队各写一个 Util,只要在不同包里就不冲突。 访问范围:包可以规定哪些东西对外可见、哪些只在包内用。 这两件事在小项目里感觉不到,在大项目里是生死问题。

二、实测模块

实测当前进程:已加载 111 个模块,顶层 96 个、子模块 15 个。 子模块的名字带点:collections.abc、ctypes._endian、ctypes.wintypes。 那个点就是分隔符——点前面是包,点后面是包里的模块。

三、同名不同物

构造两个模块里的同名类:shop.util 里的 Util.kind 是商品,crm.util 里的 Util.kind 是客户。 实测:两个类名一样(True),但是同一个类吗(False)。 它们前面各自挂着一串前缀——那串前缀就是命名空间。 没有它,两个团队的 Util 只能有一个名字。

四、为什么这是协作的前提

命名空间把【同名】变成【不同】。 它让两个团队可以互不商量地给东西起名——这在大团队里是唯一可行的办法。 代价是名字变长了(要写全路径),所以语言又给了 import 别名来缓解。 这一条与第 6 章的重用直接相关:复用别人的东西,第一步是能叫出它的全名。

五、动手 Demo:进化的 OOP 结构之一——包

先看真实进程里有多少模块、多少子模块。 再构造两个同名类,看它们是不是同一个。

import sys
total = len(sys.modules)
dotted = [n for n in sys.modules if "." in n]
print(total, total - len(dotted), len(dotted))

def make(tag):
    class Util:
        kind = tag
    return Util

u_shop, u_crm = make("商品"), make("客户")
print(u_shop.__name__ == u_crm.__name__)   # 名字一样
print(u_shop is u_crm)                    # 但不是同一个

实跑输出:

--------------------------------------------------------------------
进化的 OOP 结构之一——包
--------------------------------------------------------------------

  【包】解决的是**命名撞车**和**访问范围**。
  两个团队各写一个 `Util` 类,**只要在不同包里就不冲突。**

  实测当前进程已加载模块:**111 个**

      顶层模块(名字不带点)   96 个
      子模块(名字带点)       15 个
      子模块举例               collections.abc/ctypes._endian/ctypes.wintypes

  **但包的价值不在【模块多】,在【同一个名字放进不同前缀,就是两个东西】。**
  构造同名类实测一下:

      shop.util 里的 Util.kind  → 商品
      crm.util  里的 Util.kind  → 客户
      两个类名一样吗            → True
      是同一个类吗              → False

  实测:**名字一模一样,类是两个。**它们前面各自挂着一串前缀。
  **那串前缀就是命名空间**——没有它,两个团队的 `Util` 只能有一个名字。
  **命名空间把【同名】变成【不同】——这是大规模协作的前提。**

实测:已加载 111 个模块(顶层 96、子模块 15);两个同名类名一样但不是同一个类。 前缀就是命名空间——它把【同名】变成【不同】,这是大规模协作的前提。

30 秒实验

  1. 在你项目里找两个同名文件或同名类,看它们靠什么区分。
  2. 试一试给一个模块起别名,感受一下长名字的代价。

常见误区

  1. 以为包只是【文件夹分类】。它决定的是名字的含义。
  2. 以为同名就一定冲突。不同前缀下是两个东西。
自测三问(点开对答案) 1. 包解决哪两个问题? —— 命名撞车和访问范围:不同包里可以有同名的类,包也能规定哪些东西对外可见。 2. 两个同名类实测结果是什么? —— 类名一样(True),但不是同一个类(False)——因为前缀不同,命名空间不同。 3. 包为什么是大规模协作的前提? —— 它把同名变成不同,让两个团队可以互不商量地起名;代价是名字变长。

相关笔记