当前位置: 首页 > java >正文

Python 10天冲刺《__slots__ 是一个类级属性》用于限制和优化对象的属性存储

在 Python 中,__slots__ 是一个类级属性,用于限制和优化对象的属性存储。通过定义 __slots__,可以显著减少对象的内存占用,并提升属性访问的性能。以下是关于 __slots__ 的详细解释和使用示例:


1. 基本概念

  • 作用
    __slots__ 告诉 Python 解释器,一个类的实例只能拥有特定的属性(即声明在 __slots__ 中的属性),而不再使用 __dict__(对象的默认属性字典)来存储属性。
  • 目的
    主要用于优化内存和性能,适用于大量实例化对象的场景(如数据结构、持久化存储等)。

2. 基础用法

定义 __slots__

在类中定义 __slots__,并指定允许的属性名称:

class Point:__slots__ = ('x', 'y')  # 或者用元组或列表:__slots__ = ['x', 'y']def __init__(self, x, y):self.x = x          # 允许访问的属性self.y = y
限制属性

尝试添加未声明的属性会引发错误:

p = Point(1, 2)
p.z = 3  # 抛出 AttributeError: 'Point' object has no attribute 'z'

3. 核心原理

替代 __dict__
  • 普通类:对象默认使用 __dict__ 字典存储所有属性,灵活性高,但内存开销大。
  • 使用 __slots__:对象属性直接存储在固定的位置(类似 C 结构体的字段),无需字典,节省内存。
import sysclass WithoutSlots:def __init__(self, x, y):self.x = xself.y = yclass WithSlots:__slots__ = ('x', 'y')def __init__(self, x, y):self.x = xself.y = y# 计算内存占用
print(sys.getsizeof(WithoutSlots(1, 2)))  # 可能输出: 64 字节(包含 __dict__)
print(sys.getsizeof(WithSlots(1, 2)))     # 可能输出: 40 字节(无 __dict__)
性能提升
  • 属性访问更快:因为属性直接通过指针访问,而不是字典查找。
  • 节省内存:尤其在创建大量对象时效果显著。

4. 高级用法

1. 继承与 __slots__
  • 如果子类未定义 __slots__,则无法使用父类的 __slots__,需显式声明:

    class Base:__slots__ = ('x', 'y')class Derived(Base):__slots__ = ()  # 必须显式声明,否则会抛出错误
    
  • 子类可以扩展父类的 __slots__

    class Derived(Base):__slots__ = ('z',)  # 新增 'z' 属性
    
2. 使用 __slots____dict__ 混合
  • 如果需要保留 __dict__ 的灵活性,可以将 '__dict__' 加入 __slots__
    class MyClass:__slots__ = ('x', '__dict__')  # 允许动态添加其他属性def __init__(self):self.y = 2  # 允许,因为有 __dict__
    
3. 元类与 __slots__
  • 元类中可以通过 __slots__ 控制属性:
    class Meta(type):__slots__ = ()  # 限制元类自身的属性class MyClass(metaclass=Meta):__slots__ = ('x',)
    

5. 注意事项

限制
  • 不能动态添加属性:只能使用 __slots__ 中声明的属性。
  • 无法使用 __dict__:如果未显式声明 '__dict__',则对象没有 __dict__ 属性。
  • 不适用于多继承:如果父类中有多个类定义了 __slots__,需要将它们的 __slots__ 合并到子类中。
    class A: __slots__ = ('a',)
    class B: __slots__ = ('b',)
    class AB(A, B): __slots__ = ()  # 需要合并父类的 slots:('a', 'b')
    
常见问题
  • 如何查看已声明的 __slots__

    print(Point.__slots__)  # 输出: ('x', 'y')
    
  • 实例是否有 __dict__

    p = Point(1, 2)
    print(hasattr(p, '__dict__'))  # 输出:False(如果未显式声明 '__dict__')
    

6. 使用场景

  • 内存密集型场景:例如存储大量数据对象(如数据库记录、日志条目)。
  • 高性能需求:需要频繁访问属性时,提升访问速度。
  • 防止属性滥用:限制对象只能拥有特定属性,避免意外修改或添加属性。

7. 示例对比

普通类 vs 使用 __slots__
import sysclass WithoutSlots:def __init__(self, x, y):self.x = xself.y = yclass WithSlots:__slots__ = ('x', 'y')def __init__(self, x, y):self.x = xself.y = y# 内存对比
print(sys.getsizeof(WithoutSlots(1, 2)))  # 64 bytes(带__dict__)
print(sys.getsizeof(WithSlots(1, 2)))     # 40 bytes(无__dict__)# 访问速度对比
import timeitdef test_normal():obj = WithoutSlots(1, 2)for _ in range(1000):obj.x += 1def test_slots():obj = WithSlots(1, 2)for _ in range(1000):obj.x += 1print("Normal class: ", timeit.timeit(test_normal, number=100000))
print("Slots class:  ", timeit.timeit(test_slots, number=100000))

8. 总结

  • 优点
    • 减少内存占用(尤其适合大量对象)。
    • 提升属性访问速度。
    • 避免意外添加属性,增强代码安全性。
  • 缺点
    • 灵活性降低,无法动态添加属性。
    • 多继承时需要谨慎处理 __slots__ 的合并。
  • 适用场景:数据结构、高性能计算、内存敏感的项目。

通过合理使用 __slots__,可以在 Python 中实现更高效、更可控的对象管理。

http://www.xdnf.cn/news/4358.html

相关文章:

  • 【JS逆向基础】WEB基础
  • CAD图纸智能搜索三大突破:图纸秒搜技术、相似度匹配与AI语义搜索
  • 【每天一个知识点】使用 apriori() 函数获取频繁项集
  • 逐次逼近式A/D转换器
  • 线性回归练习1
  • 从基础到进阶:C++ 中 find 函数的全方位解析
  • MySQL 隐式转换及整数转浮点
  • 解锁健康生活:全新养身指南
  • Leetcode Hot 100 三数之和
  • Relay算子注册(在pytorch.py端调用)
  • 卷积神经网络实战(3)
  • 【基础】Python包管理工具uv使用全教程
  • Java日期格式化方法总结
  • DApp 开发:开启去中心化应用新时代
  • Spring事务和事务传播机制
  • C语言| 递归和循环的优缺点
  • 塔能水泵节能方案:精准驱动工厂能耗优化
  • 展锐Android13禁止用户使用超级省电
  • 新一代Python专业编译器Nuitka简介
  • ROS2:自定义接口文件(无废话)
  • 多模态理论知识
  • 二叉树与堆排序(概念|遍历|实现)
  • python酒店在线预定管理系统-酒店客房管理系统-快捷酒店入住系统
  • 【Linux系统】vim编辑器的使用
  • FoMo 数据集是一个专注于机器人在季节性积雪变化环境中的导航数据集,记录了不同季节(无雪、浅雪、深雪)下的传感器数据和轨迹信息。
  • C语言编程--递归程序--求数组的最大元素值
  • 油气地震资料信号处理中的NMO(正常时差校正)
  • 【网络篇】传输层TCP协议的确认应答,超时重传机制
  • IT咨询——企业数据资产怎样评估
  • 满分PPT | 基于数据运营的新型智慧城市实践与思考智慧城市数据中台解决方案智能建筑与智慧城市建设方案