一、先懂前置知识:Python 动态绑定特点
1. 核心思路
Python 是动态语言,类定义好之后,运行时可以随便给实例加属性、加方法,不用提前在类里写好。
2. 实例演示
# 1. 空类 class Student: pass # 2. 给单个实例动态加属性 s1 = Student() s1.name = "小明" print(s1.name) # 小明 # 3. 单个实例绑定方法 from types import MethodType def set_age(self,age): self.age = age # 只绑定给s1 s1.set_age = MethodType(set_age,s1) s1.set_age(18) print(s1.age) # 18 # 新实例用不了这个方法 s2 = Student() # s2.set_age(20) 报错3. 给整个类绑定方法(所有实例通用)
def set_score(self,score): self.score = score # 直接挂载到类上 Student.set_score = set_score s1.set_score(90) s2.set_score(80) print(s1.score,s2.score)二、slots作用(重点)
1. 作用
限制类的实例只能绑定指定属性,禁止随意新增其他属性,约束实例属性,节省内存、防止乱加属性。
2. 语法格式
在类内部写:
__slots__ = ("属性1","属性2")只能写元组,放允许添加的属性名。
3. 通俗实例
# 只允许实例添加 name 和 age class Student: __slots__ = ("name","age") s = Student() s.name = "小红" s.age = 20 # 报错!score不在允许列表里 # s.score = 99报错原因:score没写入__slots__,禁止绑定。
三、slots两大使用规则
- 只约束当前父类实例,对子类默认无效
class Student: __slots__ = ("name","age") # 子类继承父类 class GradStudent(Student): pass g = GradStudent() g.score = 100 # 正常运行,不受父类slots限制- 子类也写__slots__:子类允许属性 = 子类自身属性 + 父类
__slots__属性
class GradStudent(Student): __slots__ = ("score") # 新增允许score g = GradStudent() g.name = "小李" g.age = 22 g.score = 95 # 都可以使用四、使用场景(必记)
- 大量创建同类对象(学生、用户、员工),节省内存
- 规范代码,防止别人乱给实例加无关属性
- 固定实例结构,统一代码规范
五、极简学习思路
- 无
__slots__:实例随便加属性,自由灵活 - 有
__slots__:实例只能加规定属性,严格限制 - 继承关系:父类限制管不住子类,子类要限制必须自己写
课后练习题(基础 + 进阶)
练习 1 基础题
定义一个Person类,使用__slots__限制只能添加name、gender两个属性,创建实例测试,尝试添加height看是否报错。
## 练习 1 基础题 # 定义一个`Person`类,使用`__slots__`限制只能添加`name`、`gender`两个属性,创建实例测试,尝试添加`height`看是否报错。 class Person: # __slots__ = ['name','gender']#❌️不能用列表[],要用元组() 如下 __slots__ = ('name','gender') s1=Person()#1创建实例 s1.name='小明'#2赋值 s1.gender='male'#2赋值 print(s1.name)#3打印 print(s1.gender)#3打印 # print(s1.height) s1.height='180'参考答案
class Person: __slots__ = ("name","gender") p = Person() p.name = "张三" p.gender = "男" # p.height = 180 # 运行报错练习 2 进阶题
写子类Teacher继承Person,子类新增允许属性subject,实现父类 + 子类属性都能使用。
class Person: # __slots__ = ['name','gender']#❌️不能用列表[],要用元组() 如下 __slots__ = ('name','gender') #1创建实例 s1=Person() #2赋值 s1.name='小明' s1.gender='male' #3打印 print(s1.name) print(s1.gender) print(s1.height) s1.height='180' # === class Teacher(Person): __slots__ = ('subject') s2=Teacher() s2.name='小红' s2.gender='female' # s2.subject=Teacher.subject# 删除错误多余赋值语句 s2.subject='未知' print(s2.name) print(s2.gender) print(s2.subject)参考答案
class Person: __slots__ = ("name","gender") class Teacher(Person): __slots__ = ("subject") t = Teacher() t.name = "王老师" t.gender = "女" t.subject = "数学" print(t.name,t.subject)练习 3 判断题
__slots__可以用列表[]定义属性(× 只能元组)- 父类写了
__slots__,子类自动继承限制(×)#父类和子类都写__slots__,子类才会继承父类的属性。 - 动态绑定方法不受
__slots__限制(√)
=分割线=from types import MethodType 什么意思
from types import MethodType核心作用:把普通函数,变成「类的实例方法」,让这个函数能像类里自带的方法一样,使用self访问实例的属性。
拆解理解(结合你之前的教程)
先看字面:
from types import MethodTypetypes是 Python 自带的一个「工具模块」,专门处理和 “类型” 相关的操作;MethodType是这个模块里的一个「工具类 / 函数」,核心功能是 “转换函数为实例方法”。
为什么需要它?(对应教程里的场景)
教程中,我们定义了一个普通函数
def set_age(self, age):``Student``self而
MethodType``self
结合教程实例(更直观)
from types import MethodType # 导入工具 class Student: pass # 普通函数(不是类里的方法) def set_age(self, age): self.age = age s1 = Student() # 用MethodType把set_age变成s1的实例方法,绑定给s1 s1.set_age = MethodType(set_age, s1) s1.set_age(18) # 此时能正常调用,self就是s1 print(s1.age) # 输出18,成功给s1添加age属性关键补充(小白避坑)
- 用
MethodType绑定的方法,只属于当前实例(比如上面的s1),其他实例(比如s2 = Student())不能用这个方法; - 如果想让所有实例都能用这个方法,不用
MethodType,直接给「类」绑定函数即可(教程里后面的Student.set_score = set_score)。
=分割线=理解:动态绑定方法不受__slots__限制
一句话总结
slots只管「属性」,不管「方法」!你给实例动态绑方法, 完全管不着,不会报错!
1. 先分清两个东西:属性 vs 方法
你一定要先分清这两个,不然永远晕:
属性 = 变量 / 数据
比如:
s1.name = "小明" # 属性 s1.age = 18 # 属性slots就是管这个的!
方法 = 函数 / 动作
比如:
def run(self): print("跑") s1.run = run # 方法(动态绑定)slots不管这个!
2. 直接看代码(一看就懂)
class Student: __slots__ = ('name',) # 只允许 name 属性① 绑属性(不在 slots 里 → 报错)
s1 = Student() s1.age = 18 # ❌ 报错!因为 age 不在 __slots__② 绑方法(随便绑 → 不报错!)
def set_age(self, age): self.age = age s1.set_age = set_age # ✅ 正常!不报错!结论
slots 只限制属性,不限制方法!
所以这句话是对的:
动态绑定方法不受 slots 限制(√)
3. 终极记忆口诀
- 属性 = 数据→
__slots__管 - 方法 = 函数→
__slots__不管