Python中用__slots__优化含固定长度列表的User类内存的问题
问题
我需要用Python表示大量User对象,每个对象包含user_id(字符串类型)和一组固定为20个的浮点型度量值,初始类定义如下:
from typing import List class User: user_id: str measures: List[float] # 这是一个长度为20的列表(或数组)
由于要创建大量该对象,我希望通过__slots__来节省内存,但不确定直接将列表作为__slots__属性是否能有效节省内存——因为这可能仅存储列表的指针,而非列表内的浮点值。目前我有三种实现思路:
- 思路1:将
user_id和measures加入__slots__,代码如下:
from typing import List class User: __slots__ = ['user_id', 'measures'] # 这个实现能运行,但不确定是否正确利用了slots user_id: str measures: List[float] def __init__(self, user_id: str, measures: List[float]): self.user_id = user_id self.measures = measures
但不确定该实现是否能有效利用__slots__节省内存;
- 思路2:单独声明20个度量属性(虽繁琐但已知可行):
class User: __slots__ = ['user_id', 'm1', 'm2', 'm3', 'm4', 'm5', 'm6', 'm7', 'm8', 'm9', 'm10', 'm11', 'm12', 'm13', 'm14', 'm15', 'm16', 'm17', 'm18', 'm19', 'm20'] # 非常繁琐 user_id: str m1: float m2: float # ... 剩余18个度量属性的类型声明 def __init__(self, user_id: str, measures: List[float]): self.user_id = user_id self.m1, self.m2, ..., self.m20 = measures
- 思路3:使用另一个类封装
measures。
想请教哪种方案更适合实现内存优化的需求?
最优方案分析
思路1:将user_id和measures加入__slots__
这是平衡内存优化与代码简洁性的最佳选择:
__slots__的核心作用是禁用实例默认的__dict__字典,避免每个实例因存储字典产生的额外内存开销。把user_id和measures放入__slots__后,每个User实例只会存储这两个属性的指针,不会生成冗余的__dict__,这部分的内存节省是实实在在的。- 你担心的“仅存储列表指针”是事实,但列表本身的内存开销是无法避免的——无论是否使用
__slots__,列表都会在堆中存储20个浮点数,实例中存储的始终是指向列表的指针。这个思路既保留了列表操作的便捷性,又砍掉了实例字典的内存浪费,性价比极高。
思路2:单独声明20个度量属性
这个思路的内存效率最高,但开发与维护成本极高:
- 每个浮点数直接存储在实例的内存空间中,省去了列表的指针开销和列表自身的元数据(如长度、容量等)占用的内存,确实能达到极致的内存节省。
- 但缺点非常明显:代码极度冗长,后续访问、修改或遍历度量值都需要手动处理20个属性,扩展性几乎为0,除非你对内存有极端苛刻的要求,否则不建议采用。
思路3:用另一个类封装measures
这个思路会增加内存开销,完全不符合优化需求:
- 额外的封装类实例会引入新的对象结构开销(即便封装类使用
__slots__),相当于在User实例的指针之外,又多了一个封装类实例的指针,以及封装类实例本身的内存占用,反而会让内存消耗更大,直接排除。
最终结论
优先选择思路1;如果确实需要极致内存节省且能接受繁琐代码,再考虑思路2;思路3完全不推荐用于内存优化场景。
内容的提问来源于stack exchange,提问作者Pablo
相关产品推荐
相关产品推荐

