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

实测三步:改类变量两个都变、给 u1 单独赋值只变 u1——读的时候顺着链找,写的时候只写自己那层。

📝 本节和前面几节的关系

4.6 看到 made 与 no 的差别,这一节把这句话讲成一条能用的规则。

一、这句话在说什么

实例变量像全局变量一样【谁都能用】——只要拿到那个对象。 但它的范围只到那个对象为止,不像模块级全局那样全文件都能碰。 所以准确说法是:它是【把全局变量的作用范围缩小到一个对象】。 范围一缩,3.9 说的干扰面就跟着缩。

二、实测三步

初始:User.role = 普通,u1.role 和 u2.role 都是普通。 改类变量 User.role = 管理员 之后:两个都变成管理员。 再给 u1.role = 访客 之后:只有 u1 变,u2 还是管理员。 读的时候顺着链找(实例 → 类),写的时候只写自己那层。

三、为什么第三步会【造出】一个实例变量

u1.role = 访客 看着像【改】,其实是在 u1 上新建了一个实例变量,把类的那个盖住了。 这一步之后,u1 有自己的 role,u2 没有——它们不再看同一个地方。 这就是【写只写自己那层】的具体机制。知道这一点,就不会困惑于【为什么改类变量没影响它】。

四、接回 3.9 的 480 条边

三个范围排一排:模块级全局(整个文件)→ 类变量(这个类)→ 实例变量(这一个对象)。 越往下,范围越小,干扰面越小。 480 条依赖边之所以可怕,是因为全局变量谁都能改;实例变量把那 480 条边断成一个个小圈子。 这就是 OOP 治【数据被谁改】这个病的具体手法。

五、动手 Demo:实例变量是限定访问范围的全局变量

三步走:改类变量、再给一个实例单独赋值。 看每一步有几个实例受影响。

class User:
    role = "普通"          # 类变量
    def __init__(self, name):
        self.name = name

u1, u2 = User("甲"), User("乙")
print(u1.role, u2.role)      # 都看类变量
User.role = "管理员"
print(u1.role, u2.role)      # 两个都变
u1.role = "访客"             # 在 u1 上新建实例变量
print(u1.role, u2.role)      # 只有 u1 变

实跑输出:

--------------------------------------------------------------------
实例变量是限定访问范围的全局变量
--------------------------------------------------------------------

  这句话有点绕,但它是理解【实例之间互不影响】的钥匙。
  **实例变量像全局变量一样【谁都能用】,但它只对自己那个类有效。**

      u1 = User("甲"); u2 = User("乙")
      初始:u1.role = 普通,u2.role = 普通

      改类变量 User.role = 管理员 之后:
        u1.role = 管理员,u2.role = 管理员  ← 两个都变了

      再给 u1 单独赋值 u1.role = 访客:
        u1.role = 访客,u2.role = 管理员  ← 只有 u1 变

  实测这三步说明一件事:**读的时候顺着链找(实例 → 类),写的时候只写自己那层。**

  位置           像不像全局变量     范围
  ---------------------------------------------
  模块级全局     是                 整个文件
  类变量         是                 这个类
  实例变量       是                 这一个实例

  **所以小标题这句话的准确意思是:实例变量是【把全局变量的范围缩小到一个对象】。**
  **范围一缩,3.9 说的 480 条依赖边就断成了一个个小圈子。**

实测三步:都普通 → 都管理员 → 只有 u1 变访客。 读的时候顺着链找(实例 → 类),写的时候只写自己那层——第二步的赋值其实是新建了一个实例变量。

30 秒实验

  1. 写一个带类变量的类,分别改类变量和改实例属性,观察影响范围。
  2. 找出你项目里被到处改的全局状态,看看能不能缩进某个对象。

常见误区

  1. 以为实例变量就是全局变量。范围只到那个对象。
  2. 以为给实例赋值是改类变量。那是在实例上新建一个,把类的盖住。
自测三问(点开对答案) 1. 实例变量像全局变量在哪、不像在哪? —— 像在【谁都能用】(拿到对象就行);不像在范围只到那一个对象,不是整个文件。 2. 给 u1.role 赋值时发生了什么? —— 在 u1 上新建了一个实例变量,把类变量盖住;u2 没有,所以只有 u1 变。 3. 这条性质怎么帮到 3.9 的 480 条依赖边? —— 范围从整个文件缩到一个对象,干扰面跟着缩——480 条边被断成一个个小圈子。

相关笔记