为什么大佬的类都有__slots__?这篇文章给你解答

小编最近在学习github的时候,发现很多资深开发者在开发中,会经常在类的顶部加上__slots__关键字 。小编十分好奇的去掉和添加这个关键字分别进行了项目运行,发现俩者都没什么明面上的区别,都能够运行 。

为什么大佬的类都有__slots__?这篇文章给你解答

文章插图
那么这个__slots__关键字究竟是做什么的呢?
小编通过查阅资料后,发现它主要有两个功能,我们先来说第一个功能,就是限制用户的使用 。
我们都知道python是一门非常灵活的动态语言,很多在其他语言看起来完全不能容忍的事情在Python当中是可行的,这也是Python的设计理念,为了灵活和代码方便牺牲了效率 。比如我们来看一个很简单的例子,由于Python是动态语言,所以类的成员甚至可以在类创建好了之后动态创建 。这在静态语言当中是绝对不行的,我们只能调用类当中已有的属性,是不能或者很难添加新属性的 。
比如这段代码:
class Exp:     def __init__(self):         self.a = None         self.b = None   if __name__ == "__main__":     exp = Exp()     exp.c = 3     print(exp.c)我们定义了一个类叫做Exp,我们为它创建了a和b两个成员 。但是我们在使用的时候,对c成员进行了赋值 。要知道Exp类当中是没有成员c的,但是程序并不会报错,我们这么运行了之后它会将c添加进这个实例当中 。
从一方面来看,这当然非常灵活,但是另一方面,这也留下了隐患 。如果用户随意添加属性,可能会导致未知的问题,尤其在复杂的系统当中 。所以有些时候为了严谨,我们会不希望用户做这种动态的修改 。__slots__正是用来做这个的 。
我们把这个关键字加上,再来运行结果就不一样了:
class Exp:      __slots__ = ['a', 'b']     def __init__(self):         self.a = None         self.b = None   if __name__ == "__main__":     exp = Exp()     exp.c = 3     print(exp.c)如果你运行这段代码的话,你会得到一个报错,提示你Exp这个对象当中并没有c这个成员,也就是说我们只能运用__slots__这个关键字当中定义的成员,对于没有定义的成员不能随意创建,这样就限制了用户的使用 。
虽然现在大部分人使用这个关键字都是报着这个目的,但是很遗憾的是,Python创建者的初衷其实并不是这个 。这就谈到了__slots__关键字的第二个作用,就是节省内存 。
如果了解过Python底层的实现原理,你会发现在Python当中为每一个实例都创建了一个字典,就是大名鼎鼎的__dict__字典 。正是因为背后有一个字典,所以我们才可以创造出原本不存在的成员,也才支持这样动态的效果 。我们可以人工地调用这个字典输出其中的内容,我们在加上__slots__关键字之前,输出的结果是这样的:
{'a': None, 'b': None}但是加上了这个关键字之后,会得到一个报错,会告诉你Exp这个对象当中没有__dict__这个成员 。原因很简单,因为使用dict来维护实例,会消耗大量的内存,额外存储了许多数据,而使用__slots__之后,Python内部将不再为实例创建一个字典来维护,而是会使用一个固定大小的数组,这样就节省了大量的空间 。

推荐阅读