使用__slots__节省python内存技巧

__slots__作用

__slots__有一个作用是:限制类实例绑定的属性,但是它有一个更重要的作用就是节省内存,当然更适用于数据量大的情况(万量级以上)。

__slots__节省内存的原理

class Measurement:
    def __init__(self, x, y, value):
        self.x = x
        self.y = y
        self.val = value

m1 = Measurement(1, 2, "Happy")
m2 = Measurement(7, 10, "Crazy")
m2.other = True

其实,对类的变量值进行初始化,底层是通过一个指针指向__dict__(里面包含潜在的字段名和字段值)。举个例子,上面的程序底层实现过程如下:

我们也可以通过程序查看这一底层形式: ``` print(m1.__dict__) # {'x': 1, 'y': 2, 'val': 'Happy'} print(m2.__dict__) # {'x': 7, 'y': 10, 'other': True, 'val': 'Crazy'} ``` 这就是python自定义变量底层的一个基本实现。通过对这一底层理解,我们就会知道,如果我们的实例有数百万个,那么底层会有相应数百万个字典拥有相同的key值(知识value值不同),这时非常耗内存的,这时候__slots__就发挥它的作用了。

通过__slots__,我们可以稍微调整一下类,以改变类中字段的存储方式,废弃原来那种耗费内存的1对1重复的字典分配方式。具体如下:

class Measurement:
    __slots__ = ['x', 'y', 'val']
 
    def __init__(self, x, y, value):
        self.x = x
        self.y = y
        self.val = value

这样我们底层的实现就会变为如下方式:

我们可以看出,现在字段名是与Measurement类这个类型相关联,而不是原来的与相应的实例1对1的关联。而字段值与原来的方式无差别,因为毕竟各个实例的字段名一样,可以统一存放,而字段值并不都是一样,当然对于字段值也一样的我们也统一存储(因为底层字典都是与类这个类型关联,而不是与每个实例的__dict__关联)。但对于数据量庞大的情况(数百万级以上),能够非常显著的节省内存空间(25.5GB -> 16.2GB)。

以上就是__slots__能够节省内存的原理,主要还是要搞清楚python的类变量初始化的底层操作是通过字典存储后相关联这一方式进行的,__slots__只是改变了字典key,value与实例相关联的方式,可以总结如下:

  • 默认变量实例化方法:底层实例和字典是一对一的关系

  • 加入__slots__后:底层实例和字典是多对一的关系(重复的部分)。

原文地址:https://www.cnblogs.com/wujingqiao/p/9639585.html