背景
默认情况下,Python在各实例的名为__dict__的字典里存储实例的属性。为了使用底层散列表的提升访问速度,字典会消耗大量内存。如果处理几百万个实例,每个实例有几个属性,则使用类的__slots__属性能大大节约内存。它通过在解释器中使用元组存储属性,而不是字典存储属性。
NOTE:Python只会使用类中自己定义的slots,不能继承。
使用方式
定义__slots__的方式是,在类中创建一个名为__slots__的类属性。并把它的值设为一个由字符串构成的可迭代对象,各个元素表示个实例属性。个人建议使用元组,这样定义的__slots__章所好的信息就不会变化,如:
class Vector2d:
__slots__ = ('__x', '__y')
typecode = 'd'
....
在类中定义__slots__属性的目的是告诉解释器:这个类中的所有属性都在这里。这样Python会在各个实例中使用类似元组的结构存储实例变量。 如果要处理数百万个数值对象,应该使用Numpy数组。Numpy数组能高效使用内存,且提供了高度优化的数值处理函数,其中很多都一次操作整个数组。1千万个Vector2d实例使用__dict__属性时消耗1.5GB内存,而使用__slots__属性是,RAM用量可降到655MB。
__slots__的问题
__slots__能显著节省内存,不过要注意一下几点:
- 每个子类都要定义__slots__属性,因为解释器会忽略继承的__slots__属性
- 实例只能拥有__slots__中列出的属性。
总结
__slots__属性不能滥用,不能使用它限制用户能赋值的属性。其目的是节省内存,限定属性只是其副作用。处理列表数据时__slots__属性最有用,如模式固定的数据库记录,及特大型数据集。如果经常处理大量数据,一定要了解一下Numpy和数据分析库pandas.
Reference
«Fluent Python»