Python中__slots__属性介绍与基本使用方法
作者:严北 发布时间:2023-11-22 02:45:59
简介
在廖雪峰的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


猜你喜欢
- 我们在做自动化运维的时候,经常需要调用api中的接口,不过很多人不知道具体的调用方法,在学习python中的requests库后,我们就可以
- 代码很简单,只需要2行代码就可实现想要的功能,虽然很短,但确实使用,主要使用了requests库。测试2XX, 3XX, 4XX, 5XX都
- 问题你想使用原始文件名执行文件的I/O操作,也就是说文件名并没有经过系统默认编码去解码或编码过。解决方案默认情况下,所有的文件名都会根据 s
- 看这个模块要先看with as的用法,最常用的方法就是打开一个文件:with open(“filename”) as f:f.read()w
- 网页过渡是指当浏览者进入或离开网页时,页面呈现的不同的刷新效果,比如卷动、百叶窗等。注:通过模板所建网页无法添加网页过渡效果!制作步骤:1、
- /************************* Sql Server 2000 如何删除数据库备份 *****************
- 项目运行环境阿里云(单核CPU, 1G内存, Ubuntu 14.04 x64 带宽1Mbps), 具体购买和ssh连接阿里云本文不做描述。
- Python连接MySQL,进行数据库表变更和查询:python mysql insert delete query:#!/usr/bin/
- docker-compose.yal文件中: redis: image: redis container_name:
- 目录ORM是什么实现ORM中的insert功能完善对数据类型的检测抽取到基类中添加数据库驱动执行sql语句添加数据库驱动执行sql语句测试功
- 太多的小伙伴正在学习Python,就说自己以后要做全栈开发,大家知道这是做什么的吗?我们现在所知道的知识点,哪些是以后你要从事这个全栈所需要
- 一、基于PaddleSpeech的婴儿啼哭识别1.项目背景对婴儿来说,啼哭声是一种通讯的方式,一个非常有限的,但类似成年人进行交流的方式。它
- 模板是一个文本,用于分离文档的表现形式和内容。 模板定义了占位符以及各种用于规范文档该如何显示的各部分基本逻辑(模板标签)。 模板通常用于产
- 使用MySQL进行数据库备份,有很正规的数据库备份方法,同其他的数据库服务器有相同的概念,但有没有想过,MySQL会有更简捷的使用文件目录的
- 首先如果柱状图中有中文,比如X轴和Y轴标签需要写中文,解决中文无法识别和乱码的情况,加下面这行代码就可以解决了:plt.rcParams[&
- 本文教大家使用了laydate插件设置开始和结束时间,供大家参考,具体内容如下用的laydate插件是layDate-v5.0.6,是新版本
- 增加中间件可以选择普通模式和LUA脚本模式,建议选择普通模式,实际上不需要控制的那么精确。package Middlewaresimport
- 从过往MySQL数据库生产环境的维护工作中,总结的一些小经验和知识,未必有多深奥,但是对我们消除隐患,确保MySQL数据库生产环境四个9的作
- 引言我们经常听到"因为GIL的存在,python的多线程不能利用多核CPU",现在我们暂且不提GIL,python能不能
- WebDriver内置了测试中捕获屏幕并保存的方法。示例脚本:(1)save_screenshot(filename):保存屏幕截图from