Python中__slots__属性介绍与基本使用方法


Posted in Python onSeptember 05, 2018

简介

在廖雪峰的python网站上,他是这么说的

python是动态语言,它允许程序在执行过程中动态绑定属性或者方法(使用MethodTpye)。

某个实例在执行过程中绑定的属性跟方法,仅在该实例中有效,其他同类实例是没有的。

可以通过给class绑定属性/方法,来给所有实例绑定属性/方法:

Student.name = ''
Student.set_score = set_score

而如果使用__slots__,它仅允许动态绑定()里面有的属性

例如,下面这样会报错

class Student():
__slots__ = ('name', 'age')

S1 = Student()
S1.name = 'Jack' # ok!
S1.score = 123 # error!

但是我觉得很奇怪,仅有这一个作用吗?于是我再查了其他资料,发现这个函数可以很可观地节约内存,下面来一起看看详细的介绍吧。

__slots__允许我们声明并限定类成员,并拒绝类创建__dict__和__weakref__属性以节约内存空间。

Python是动态语言,对于普通的类,可以为类实例赋值任何属性,这些属性会存储在__dict__中:

>>> class Student(object):
... pass
... 
>>> Abey = Student()
>>> Abey.name = 'Abey'
>>> Abey.__dict__
{'name': 'Abey'}

这样的特性带来两个问题:

  • 数据通过字典(Hash)存储所占用的空间较大
  • 如何禁止随意生成类属性

当然,__slots__就能解决这两个问题。通过__slots__属性限定类属性的创建:

>>> class Student(object):
... __slots__ = ('name', 'age')
... 
>>> Abey = Student()
>>> Abey.name = 'Abey'
>>> Abey.gender = 'Female'
Traceback (most recent call last):
 File "<input>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'gender'
>>> Abey.__dict__
Traceback (most recent call last):
 File "<input>", line 1, in <module>
AttributeError: 'Student' object has no attribute '__dict__'

可以看到,在定义了__slots__变量后,Student类实例已经不能随意创建不在__slots__定义内的属性gender,同时实例中也不再有__dict__结构。

用法

继承树

__slots__在继承中有两种表现:

  • 子类未声明__slots__时,不继承父类的__slots__,即此时子类实例可以随意赋值属性
  • 子类声明__slots__时,继承父类的__slots__,即此时子类的__slots__为其自身+父类的__slots__

以下面的父类为例:

>>> class Student(object):
... __slots__ = ('name', 'age')
...

创建一个子类不声明__slots__,该类实例可以创建父类__slots__限定之外的属性gender:

>>> class SubStudent(Student):
... pass
... 
>>> Bob = SubStudent()
>>> Bob.gender = 'Male'
>>> Bob.__dict__
{'gender': 'Male'}

而创建一个声明__slots__的子类,该类属性则只能创建父类__slots__+自身__slots__限定的属性:

>>> class SubStudent2(Student):
... __slots__ = 'gender'
... 
>>> Cathy = SubStudent2()
>>> Cathy.gender = 'Female'
>>> Cathy.name = 'Cathy'
>>> Cathy.teacher = 'Mrs. Wang'
Traceback (most recent call last):
 File "<input>", line 1, in <module>
AttributeError: 'SubStudent2' object has no attribute 'teacher'

注意:子类的__slots__本身已经继承自父类,无需重复声明父类已声明的属性。例如上例,重复声明会多占用内存空间:

>>> class SubStudent3(Student):
... __slots__ = ('name', 'age', 'gender')
... 
>>> from sys import getsizeof
>>> getsizeof(Student()), getsizeof(SubStudent2()), getsizeof(SubStudent3())
(56, 64, 80)

性能对比

我们为什么要使用__slots__呢?

更快速地赋值属性

参考Stack Overflow回答中给出的数据:

import timeit

class Foo(object): __slots__ = 'foo',

class Bar(object): pass

slotted = Foo()
not_slotted = Bar()

def get_set_delete_fn(obj):
 def get_set_delete():
 obj.foo = 'foo'
 obj.foo
 del obj.foo
 return get_set_delete

得到测试结果为:

>>> min(timeit.repeat(get_set_delete_fn(slotted)))
0.2846834529991611
>>> min(timeit.repeat(get_set_delete_fn(not_slotted)))
0.3664822799983085

可以看到,在相同的环境(Ubuntu)下,slots为Python3.5带来了接近30%的赋值速度提升:

节约内存空间

>>> 0.3664822799983085 / 0.2846834529991611
1.2873325658284342

由于不使用__dict__存储对象的属性,__slots__在一些场景下能够节约极大的内存空间。具体数据可以查看参考中的回答链接,不赘述。

参考

[1] Usage of __slots__? ,  Aaron Hall, Stack Overflow

推荐阅读

[1] Data model , Python Document

[2] python __slots__ 使你的代码更加节省内存 , david_bj, 51CTO

[3] 使用__slots__ , 廖雪峰

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
盘点提高 Python 代码效率的方法
Jul 03 Python
Python lxml模块安装教程
Jun 02 Python
初步剖析C语言编程中的结构体
Jan 16 Python
Python对字符串实现去重操作的方法示例
Aug 11 Python
python 按不同维度求和,最值,均值的实例
Jun 28 Python
如何在python字符串中输入纯粹的{}
Aug 22 Python
实例讲解Python中浮点型的基本内容
Feb 11 Python
使用pyqt5 tablewidget 单元格设置正则表达式
Dec 13 Python
python实现梯度下降和逻辑回归
Mar 24 Python
Python如何实现的二分查找算法
May 27 Python
解决Tensorflow2.0 tf.keras.Model.load_weights() 报错处理问题
Jun 12 Python
Python自动化之批量处理工作簿和工作表
Jun 03 Python
python使用xlrd和xlwt读写Excel文件的实例代码
Sep 05 #Python
python 3调用百度OCR API实现剪贴板文字识别
Sep 04 #Python
Python实现监控键盘鼠标操作示例【基于pyHook与pythoncom模块】
Sep 04 #Python
Python使用pyautogui模块实现自动化鼠标和键盘操作示例
Sep 04 #Python
Python PyAutoGUI模块控制鼠标和键盘实现自动化任务详解
Sep 04 #Python
selenium+python实现自动化登录的方法
Sep 04 #Python
python使用scrapy发送post请求的坑
Sep 04 #Python
You might like
用PHP开发GUI
2006/10/09 PHP
php抽象类用法实例分析
2015/07/07 PHP
php调用自己java程序的方法详解
2016/05/13 PHP
Laravel多用户认证系统示例详解
2018/03/13 PHP
php使用curl获取header检测开启GZip压缩的方法
2018/08/15 PHP
php中字符串和整数比较的操作方法
2019/06/06 PHP
js escape,unescape解决中文乱码问题的方法
2010/05/26 Javascript
对setInterval在火狐和chrome切换标签产生奇怪的效果之探索,与解决方案!
2011/10/29 Javascript
Jquery树插件zTree用法入门教程
2015/02/17 Javascript
JS实现网页顶部向下滑出的全国城市切换导航效果
2015/08/22 Javascript
使用JavaScript脚本无法直接改变Asp.net中Checkbox控件的Enable属性的解决方法
2015/09/16 Javascript
jQuery鼠标悬浮链接弹出跟随图片实例代码
2016/01/08 Javascript
jquery自定义表单验证插件
2016/10/12 Javascript
使用Electron构建React+Webpack桌面应用的方法
2017/12/15 Javascript
原生JS实现逼真的图片3D旋转效果详解
2019/02/16 Javascript
微信小程序学习笔记之登录API与获取用户信息操作图文详解
2019/03/29 Javascript
JavaScript 扩展运算符用法实例小结【基于ES6】
2019/06/17 Javascript
小程序跳转到的H5页面再跳转回跳小程序的方法
2020/03/06 Javascript
python中zip和unzip数据的方法
2015/05/27 Python
Python如何判断数独是否合法
2016/09/08 Python
浅谈flask中的before_request与after_request
2018/01/20 Python
css 元素选择器的简单实例
2016/05/23 HTML / CSS
使用纯 CSS 创作一个脉动 loader效果的源码
2018/09/28 HTML / CSS
哈利波特商店:Harry Potter Shop
2018/11/30 全球购物
运动鞋、足球鞋和慕尼黑球衣:Sport Münzinger
2019/08/26 全球购物
俄罗斯外国汽车和国产汽车配件网上商店:Движком
2020/04/19 全球购物
Java的for语句中break, continue和return的区别
2013/12/19 面试题
制冷与电控专业应届生求职信
2013/11/11 职场文书
生日邀请函范文
2014/01/13 职场文书
二年级评语大全
2014/04/23 职场文书
环保志愿者活动总结
2014/06/27 职场文书
史上最牛的辞职信
2015/02/28 职场文书
汽车4S店前台接待岗位职责
2015/04/03 职场文书
2015年保育员个人工作总结
2015/05/13 职场文书
校园音乐节目广播稿
2015/08/19 职场文书
MySQL约束超详解
2021/09/04 MySQL