简介
在廖雪峰的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__"external nofollow" target="_blank" href="https://stackoverflow.com/questions/472000/usage-of-slots">Data model , Python Document
[2] python __slots__ 使你的代码更加节省内存 , david_bj, 51CTO
[3] 使用__slots__ , 廖雪峰
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
RTX 5090要首发 性能要翻倍!三星展示GDDR7显存
三星在GTC上展示了专为下一代游戏GPU设计的GDDR7内存。
首次推出的GDDR7内存模块密度为16GB,每个模块容量为2GB。其速度预设为32 Gbps(PAM3),但也可以降至28 Gbps,以提高产量和初始阶段的整体性能和成本效益。
据三星表示,GDDR7内存的能效将提高20%,同时工作电压仅为1.1V,低于标准的1.2V。通过采用更新的封装材料和优化的电路设计,使得在高速运行时的发热量降低,GDDR7的热阻比GDDR6降低了70%。
更新日志
- 中国武警男声合唱团《辉煌之声1天路》[DTS-WAV分轨]
- 紫薇《旧曲新韵》[320K/MP3][175.29MB]
- 紫薇《旧曲新韵》[FLAC/分轨][550.18MB]
- 周深《反深代词》[先听版][320K/MP3][72.71MB]
- 李佳薇.2024-会发光的【黑籁音乐】【FLAC分轨】
- 后弦.2012-很有爱【天浩盛世】【WAV+CUE】
- 林俊吉.2012-将你惜命命【美华】【WAV+CUE】
- 晓雅《分享》DTS-WAV
- 黑鸭子2008-飞歌[首版][WAV+CUE]
- 黄乙玲1989-水泼落地难收回[日本天龙版][WAV+CUE]
- 周深《反深代词》[先听版][FLAC/分轨][310.97MB]
- 姜育恒1984《什么时候·串起又散落》台湾复刻版[WAV+CUE][1G]
- 那英《如今》引进版[WAV+CUE][1G]
- 蔡幸娟.1991-真的让我爱你吗【飞碟】【WAV+CUE】
- 群星.2024-好团圆电视剧原声带【TME】【FLAC分轨】