-类 Lecture 11 - Classes
Python 类与面向对象
看完你能亲手写出一个完整的类并讲清每个成员的来龙去脉
按 空格/→ 演示下一步
全部页面点击任意一页,跳回舞台从这页播放
Python 类与面向对象
看完你能亲手写出一个完整的类并讲清每个成员的来龙去脉
为什么需要类
我们用字典和列表组织过学生信息:姓名、成绩散落在不同结构里,靠位置和键名记忆。这正是内置类型暴露的边界。
图纸定义结构,对象是按图盖出的具体房子
内置类型 vs 用户定义类型
int/str 看似基本值,实是对象;自定义类看似新东西,本质也是对象。真实分界在哪?
- Python 自带,C 实现于解释器
- 字面量直接写出就是对象
- 行为固定,不能改内部方法
- 开发者用 class 关键字自己写
- 必须调用类名加括号实例化
- 可继承/重写,行为完全可定制
类的基本语法
用最少代码演示三件事:class 关键字、大驼峰命名、pass 占位。
L2 是声明入口;L3 解决空类体的语法陷阱;L7 证明该类已成为运行时类型。
创建类的实例
前面我们写好了类的『图纸』,但图纸本身盖不出能住的房子。要住人,还得拿图纸实实在在地盖一栋——这个动作,就是实例化。
图纸是类,每栋盖好的房是独立实例,互相不影响
实例化环境图
顺箭头读:上方是类定义后的状态,下方是实例化流水线。虚线箭头表示属性查找时实例向类的回溯方向。
实例属性
上一页我们画出实例的环境图,看到每个实例都有自己独立的命名空间。这一页聚焦那个空间里真正存放的"数据"——实例属性,并比较它和类中定义的变量到底有什么区别。
校规全校共享一份,个人成绩每人各自一份
属性查找链
从 obj.attr 出发,沿实例→类→父类→object 逐级查找的决策路径
什么是方法
上页我们沿属性查找链追到类。但若在类里找到的是一个函数,Python 不会原样返回——它会先把实例绑进去,再交还给你。这个绑定动作,正是方法的灵魂。
医生(方法)绑定一位患者(实例 self),直接调取其病历(属性)
方法的定义语法
用计数器实例展示类内 def 语法:self 绑定当前实例,amount 可省略并采用默认值。
add 的 self 在实例调用时自动绑定;amount 默认 1。counter.add(3) 覆盖默认值,counter.add() 沿用默认值。
self 参数详解
前面知道,方法定义在类里,调用却要通过某个实例。方法要读写属性时,必须先拿到“这个实例”,self 就是专门接住它的第一个参数,再从这里访问实例数据。
桌号对应对象,self 对应该实例;方法凭它找到并修改这张桌子的状态
初始化方法 __init__
演示 __init__ 在实例化时如何自动执行,以及如何把参数写入实例属性。
L4 定义 __init__;L6 把参数写入 self;L13 实例化时自动调用 __init__;L14 验证属性已生效。
方法调用环境变化
看一次方法调用中栈帧的诞生与销毁。从左到右扫参与方,从上到下扫消息。
整数集合需求分析
上一节我们学会了写方法,但「能写」和「会设计」差得很远。设计 SetOfIntegers 的第一步,不是敲代码,而是想清楚——它究竟要做什么、边界在哪。
投进去=add,掏出来=remove,摸一下=成员判断
类的完整实现
把 IntSet 类一次性看全:六个方法各司其职,组成真正可用的集合。
高亮行就是类的骨架:__init__ 建属性、insert 去重、__contains__ 让 in 工作、remove 抛自定义错误、__repr__ 控制显示——六个方法拼出最小可用类。
集合类环境图
从全局帧出发,沿「类定义→实例化调用→__init__执行」三段路径,看实例对象与属性的最终归属。
自测检验
Python 中执行 obj.attr 时,若实例上没有该属性,Python 会按什么顺序继续查找?
课后思考
先自己思考再看答案。三题分别对应回顾、应用与边界。
参考答案这只是约定不是语法要求。Python 不管第一参数叫什么都会传入实例,改名 this 照样运行。但违反 PEP 8 约定会让代码难以阅读。
参考答案函数体外属性在类定义时只求值一次;__init__ 在每次实例化时执行,对实例赋同名属性后会「遮蔽」类属性。从实例访问时先查实例,查不到再查类。
参考答案会看到,因为实例查找属性时找不到就上溯到类。但若已有实例在 __init__ 中给同名属性赋值过,就形成「实例遮蔽」,后续修改类属性对它们不再生效。