使用__slots__

Python动态绑定与__slots__

正常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性。先定义class:

class Student(object):
    pass
然后,尝试给实例绑定一个属性:
>>> s = Student()
>>> s.name = 'Michael' # 动态给实例绑定一个属性
>>> print(s.name)
Michael
还可以尝试给实例绑定一个方法:
>>> def set_age(self, age): # 定义一个函数作为实例方法
...     self.age = age
...
>>> from types import MethodType
>>> s.set_age = MethodType(set_age, s) # 给实例绑定一个方法
>>> s.set_age(25) # 调用实例方法
>>> s.age # 测试结果
25
但是,给一个实例绑定的方法,对另一个实例是不起作用的:
>>> s2 = Student() # 创建新的实例
>>> s2.set_age(25) # 尝试调用方法
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'set_age'
为了给所有实例都绑定方法,可以给class绑定方法:
>>> def set_score(self, score):
...     self.score = score
...
>>> Student.set_score = set_score
给class绑定方法后,所有实例均可调用:
>>> s.set_score(100)
>>> s.score
100
>>> s2.set_score(99)
>>> s2.score
99
通常情况下,上面的set_score方法可以直接定义在class中,但动态绑定允许我们在程序运行的过程中动态给class加上功能,这在静态语言中很难实现。
使用__slots__
但是,如果我们想要限制实例的属性怎么办?比如,只允许对Student实例添加name和age属性。
为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性:
class Student(object):
    __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
然后,我们试试:
>>> s = Student() # 创建新的实例
>>> s.name = 'Michael' # 绑定属性'name'
>>> s.age = 25 # 绑定属性'age'
>>> s.score = 99 # 绑定属性'score'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'
由于'score'没有被放到__slots__中,所以不能绑定score属性,试图绑定score将得到AttributeError的错误。
使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的:
>>> class GraduateStudent(Student):
...     pass
...
>>> g = GraduateStudent()
>>> g.score = 9999
除非在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__。

<think>好的,我现在需要解释Python中的__slots__,用户之前已经询问过__init__和__new__的区别,现在可能想进一步了解如何优化类或管理属性。首先,我需要回想__slots__的作用,它主要用于限制类实例可以添加的属性,并且能节省内存。接下来,我需要整理主要知识点,比如内存优化、属性限制、与普通类的对比等。 用户可能想知道为什么使用__slots__,使用场景,以及注意事项。我需要确保解释清晰,结构合理,可能还要包括代码示例来展示效果。记得之前回答过__init__和__new__,所以可能需要保持一致的格式,比如分点说明、代码块和实际应用场景。 需要注意不要遗漏关键点,比如__slots__如何影响继承,或者无法使用弱引用的情况。同时,避免技术术语过多,用简单的中文解释。可能还需要比较使用__slots__前后的内存占用差异,用示例说明。 另外,用户可能关心使用后的性能提升,比如属性访问速度是否加快,这也是需要提到的。最后,总结适用场景,帮助用户判断何时该使用__slots__。检查是否有错误,比如是否正确处理了继承中的__slots__问题,或者是否提到动态添加属性的限制。确保所有信息准确,并且以用户容易理解的方式呈现。</think>在 Python 中,`__slots__` 是一个特殊的类属性,主要用于优化内存占用和控制实例属性。以下是它的核心要点和用法: ```python class User: __slots__ = ('name', 'age') # 明确声明允许的属性 def __init__(self, name, age): self.name = name self.age = age # 普通类对比 class FreeUser: pass ``` **三大核心作用** 1. **内存优化** 通过固定属性存储方式(取消实例的 `__dict__` 字典),可显著减少内存占用: ```python from sys import getsizeof print(getsizeof(User('Alice', 30))) # 典型输出:56 print(getsizeof(FreeUser())) # 典型输出:152(多出近 3 倍) ``` 2. **属性限制** 严格约束实例可拥有的属性: ```python u = User('Bob', 25') u.gender = 'male' # 抛出 AttributeError ``` 3. **加速访问** 通过预定义属性存储结构,提升属性访问速度(约快 20-30%) **实现原理对比表** | 特性 | 普通类(有 `__dict__`) | 使用 `__slots__` 的类 | |-------------------|------------------------|-----------------------| | 动态添加属性 | ✔️ 允许 | ❌ 禁止 | | 内存占用 | 较高 | 较低 | | 属性访问速度 | 较慢 | 较快 | | 继承机制 | 自动继承 | 需显式声明 | **典型使用场景** - 需要创建海量实例(如游戏中的粒子系统) - 严格限制类的属性字段(如数据验证类) - 需要提升高频访问属性的性能 **注意事项** 1. 继承时需要处理 `__slots__` 的合并: ```python class Student(User): __slots__ = ('grade',) # 必须显式声明,否则会恢复 __dict__ # 父类的 __slots__ 自动合并 ``` 2. 不可与以下特性同时使用: - `@property` 装饰器(需要特殊处理) - 弱引用(需额外添加 `__weakref__` 到 `__slots__`) 3. 无法通过 `vars(obj)` 查看属性(因为没有 `__dict__`) **实际应用案例** ```python class Vector3D: __slots__ = ('x', 'y', 'z') def __init__(self, x, y, z): self.x = x self.y = y self.z = z def __add__(self, other): return Vector3D(self.x+other.x, self.y+other.y, self.z+other.z) # 创建百万级实例可节省约 40% 内存 ``` **决策指南** ✅ 推荐使用:固定属性结构 + 大规模实例化场景 ❌ 避免使用:需要动态添加属性 + 使用弱引用等高级特性时
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值