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实现文件名批量替换和内容替换
Mar 20 Python
Python实现压缩与解压gzip大文件的方法
Sep 18 Python
python实现折半查找和归并排序算法
Apr 14 Python
python3+PyQt5实现文档打印功能
Apr 24 Python
Python 获取中文字拼音首个字母的方法
Nov 28 Python
Python实用库 PrettyTable 学习笔记
Aug 06 Python
python每天定时运行某程序代码
Aug 16 Python
python中的subprocess.Popen()使用详解
Dec 25 Python
Django Model中字段(field)的各种选项说明
May 19 Python
tensorflow基于CNN实战mnist手写识别(小白必看)
Jul 20 Python
python爬取抖音视频的实例分析
Jan 19 Python
python中time.ctime()实例用法
Feb 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实现定时生成HTML网站首页实例代码
2008/11/20 PHP
php导入excel文件到mysql数据库的方法
2015/01/14 PHP
PHP使用finfo_file()函数检测上传图片类型的实现方法
2017/04/18 PHP
IE6与IE7中,innerHTML获取param的区别
2009/03/15 Javascript
类似GMAIL的Ajax信息反馈显示
2010/02/16 Javascript
基于Jquery的标签智能验证实现代码
2010/12/27 Javascript
XMLHttpRequest处理xml格式的返回数据(示例代码)
2013/11/21 Javascript
href下载文件根据id取url并下载
2014/05/28 Javascript
jQuery实现商品活动倒计时
2015/10/16 Javascript
JavaScript中的数据类型转换方法小结
2015/10/26 Javascript
js 实现省市区三级联动菜单效果
2017/02/20 Javascript
微信浏览器禁止页面下拉查看网址实例详解
2017/06/28 Javascript
javascript中的replace函数(带注释demo)
2018/01/07 Javascript
Vue常用的几个指令附完整案例
2018/11/06 Javascript
微信小程序提取公用函数到util.js及使用方法示例
2019/01/10 Javascript
Vue实现微信支付功能遇到的坑
2019/06/05 Javascript
Python实现计算最小编辑距离
2016/03/17 Python
python函数中return后的语句一定不会执行吗?
2017/07/06 Python
python 按照固定长度分割字符串的方法小结
2018/04/30 Python
使用django实现一个代码发布系统
2019/07/18 Python
Python 3.10 的首个 PEP 诞生,内置类型 zip() 迎来新特性(推荐)
2020/07/03 Python
python3判断IP地址的方法
2021/03/04 Python
HTML5中5个简单实用的API(第二篇,含全屏、可见性、拍照、预加载、电池状态)
2014/05/07 HTML / CSS
HTML5 localStorage使用总结
2017/02/22 HTML / CSS
html5默认气泡修改的代码详解
2020/03/13 HTML / CSS
HTML5 drag和drop具体使用详解
2021/01/18 HTML / CSS
美国最大点评网站:Yelp
2018/02/14 全球购物
Booking.com英国官网:全球酒店在线预订网站
2018/04/21 全球购物
护理学中专毕业生求职信
2013/11/11 职场文书
服务承诺书怎么写
2014/05/24 职场文书
求职信结尾怎么写
2014/05/26 职场文书
爱护草坪标语
2014/06/24 职场文书
课前一分钟演讲稿
2014/08/26 职场文书
自荐信格式模板
2015/03/27 职场文书
教师年度考核自我评鉴
2015/08/11 职场文书
厉害!这是Redis可视化工具最全的横向评测
2021/07/15 Redis