1. 基本知识
__slots__
是 Python 类中的一个特殊属性,用于限制实例可以动态添加的属性,并减少内存占用
一、没有__slots__
情况:
当类没有定义 __slots__
时,每个实例会有一个默认的字典(__dict__
)来存储对象的属性
意味着可以动态添加属性,并且每个实例的内存使用会稍微多一些,因为需要存储字典
特点:
- 灵活性高,可以动态添加属性
- 由于使用字典存储属性,内存占用较多
- 属性访问速度较慢,因为字典查找涉及哈希计算
二、有__slots__
的情况:
不再为每个实例创建 __dict__
,而是直接使用一种更紧凑的数据结构来存储属性
这可以显著减少内存使用,但限制了动态添加属性
特点:
- 节省内存,因为不需要为每个实例存储字典
- 限制动态添加未在
__slots__
中定义的属性 - 属性访问速度更快,因为直接引用而非字典查找
基本的总结如表所示:
特性 | 没有 __slots__ | 有 __slots__ |
---|---|---|
内存使用 | 较高,使用字典存储属性 | 较低,使用更紧凑的数据结构 |
动态添加属性 | 允许 | 不允许,除非在 slots 中定义 |
属性访问速度 | 较慢 | 较快 |
灵活性 | 高 | 低 |
__dict__ 属性是否存在 | 存在 | 不存在 |
使用场景 | 需要动态添加属性的类 | 内存优化和确定属性的类 |
2. Demo
没有使用的情况:
class NoSlots:
def __init__(self, name, age):
self.name = name
self.age = age
# 创建实例
obj1 = NoSlots("Alice", 30)
# 动态添加属性
obj1.gender = "Female"
print(obj1.__dict__) # {'name': 'Alice', 'age': 30, 'gender': 'Female'}
使用的情况:
class WithSlots:
__slots__ = ['name', 'age']
def __init__(self, name, age):
self.name = name
self.age = age
# 创建实例
obj2 = WithSlots("Bob", 25)
# 尝试动态添加属性
try:
obj2.gender = "Male"
except AttributeError as e:
print(e) # 'WithSlots' object has no attribute 'gender'
截图如下:
再者 __slots__
的继承
class Parent:
__slots__ = ['name']
def __init__(self, name):
self.name = name
class Child(Parent):
__slots__ = ['age']
def __init__(self, name, age):
super().__init__(name)
self.age = age
# 创建实例
obj3 = Child("Charlie", 10)
# 尝试动态添加属性
try:
obj3.gender = "Male"
except AttributeError as e:
print(e) # 'Child' object has no attribute 'gender'
截图如下:
所以说
子类的 __slots__
属性是父类的 __slots__
和子类的 __slots__
的组合
仍然无法动态添加 gender 属性