📄 一句话概括
同一个类造 10000 个实例:made 只有一个、no 有 10000 个——这就是类变量和实例变量的分水岭。
📝 本节和前面几节的关系
4.5 讲盒子怎么开口,这一节讲一个盒子能复制出多少个。
一、为什么这条重要
只有一个对象,那叫单例;类之所以是类,是它能造很多个。 而且每个都要有自己的状态——否则就不叫 10000 个,叫 1 个被反复覆盖。 这一条同时支撑了多态和内存两件事:每个对象自己算,每个对象自己占一块。
二、实测 10000 个
ts = [Ticket(i) for i in range(10000)]。
实测:造出 10000 个,编号 0 到 9999,互不相同。
Ticket.made 是 10000,ts[0].no 是 0,ts[9999].no 是 9999。
同一个类,一万份状态,各不相干。
三、两个名字,两种东西
made 写在类里——类变量,只有 1 个,全体共享。
no 写在 self 上——实例变量,每个实例 1 个。
同一个名字在类和实例上,是两个不同的东西。4.7 专门讲这件事。
判断办法:在 __init__ 里 self.x = ... 的是实例变量;写在类体里的是类变量。
四、这条功能支撑了什么
多态要靠它——每个对象按自己的类型算,前提是它有自己的状态。 内存那一章要靠它——每次 new 都占一块堆,第 5 章讲这块怎么分。 没有【创建很多个】,前两条都无从谈起。
五、动手 Demo:类的功能之三——创建很多个
一个类造 10000 个实例,看每个是不是都有自己的状态。 再对比类变量和实例变量:同一个类里,一个只有一个,一个有 10000 个。
class Ticket:
made = 0 # 类变量:全体共享
def __init__(self, no):
self.no = no # 实例变量:每个一份
Ticket.made += 1
ts = [Ticket(i) for i in range(10000)]
print(Ticket.made, ts[0].no, ts[-1].no)
print(len(set(t.no for t in ts)))
实跑输出:
--------------------------------------------------------------------
类的功能之三——创建很多个
--------------------------------------------------------------------
同一个类,可以造出很多个各自独立的实例。**这是类区别于【单例对象】的关键。**
实测造 10000 个,看每个是不是都有自己的状态:
ts = [Ticket(i) for i in range(10000)]
造出来的个数 10000
第一个编号 0
最后一个编号 9999
编号互不相同吗 是
**注意 `made` 和 `no` 的区别**:
写在哪 有几个
-----------------------------------------------------
made 类里(类变量) 只有 1 个,全体共享
no self 上(实例变量) 每个实例 1 个
实测确认:**`made` 是 10000,`ts[0].no` 是 0,`ts[9999].no` 是 9999。**
**同一个名字在类上和实例上,是两个不同的东西**——4.7 专门讲这件事。
实测:made 是 10000,ts[0].no 是 0,ts[9999].no 是 9999,编号互不相同。
同一个名字在类上和实例上,是两个不同的东西——made 只有一份分享,no 每个一份。
30 秒实验
- 给你的类加一个计数器,看它统计的是实例个数还是某个字段之和。
- 想一想:如果
made写成了self.made,会发生什么。
常见误区
- 以为类只能有一个对象。造很多个才是类的常态。
- 以为类变量和实例变量是同一件事。一个共享、一个各有一份。
自测三问(点开对答案)
1. 造 10000 个实例后,`made` 和 `no` 各是什么? —— `made` 是 10000(类变量,只有一份共享);`no` 每个实例一份,从 0 到 9999。 2. 怎么区分类变量和实例变量? —— 写在类体里的是类变量;在 `__init__` 里用 `self.x = ...` 赋值的是实例变量。 3. 这条功能支撑了哪两件事? —— 多态(每个对象按自己的类型算)和内存(每次 new 都占一块堆)。- ☐ 下一节(4.7 实例变量是限定访问范围的全局变量)
相关笔记
- 实例变量是限定访问范围的全局变量 — 这两个名字的准确含义
- 三大要素之二:实现调用端公用化的多态 — 靠它才成立
- 🔵 计算机基础 · 索引 — 对象在内存里怎么放
- 🧩 面向对象是怎样工作的 · 索引