Python __slots__的使用方法


Posted in Python onNovember 15, 2020

准备

正常情况下,创建class的实例后,可以给该实例绑定任何属性和方法,这就是动态语言的灵活性。首先定义一个class

class A(object):
  pass

然后创建一个实例,并给实例添加属性和方法。

a = A()
print a.__dict__   #{}
A.name = 'xiaoming' #动态的给实例绑定属性,其实例属性会保存到实例的__dict__中
print a.__dict__   #{'name': 'xiaoming'}
f = lambda :100
a.fun = f      
print a.__dict__   #{'fun': <function <lambda> at>, 'name': 'xiaoming'}

此时的name属性和fun()方法只有实例a能使用,类A的其他实例不能使用,如果想让类A的所有实例都能使用,我们需要给类A绑定方法

print A.__dict__   #...
f = lambda :100
A.fun = f      
print A.__dict__   #... + 'fun': <function <lambda> at 0x0000000003582978>

此时,类A的所有实例就能使用方法fun()了。

​ 通常情况下,上面的fun()方法应该定义在class中,但动态绑定允许在程序运行的过程中动态的给class增加功能,这在静态语言中很难实现,这也是动态语言的优点。

__slots__

​ 如果在一个类中定义了__slots__属性,那么这个类的实例将不会拥有__dict__属性,没有__dict__的实例也就不能添加实例属性了。简单来说,__slots__的作用就是阻止类在实例化时为实例分配__dict__属性,限制该实例能添加的属性。

作用

​ 通常情况下实例使用__dict__来存储自己的属性,它允许实例动态地添加或删除属性。然而,对一些在编译期就已经知道有什么变量的类或者不允许动态添加变量的类来说,它们并不需要动态地添加变量。如果想要限制实例属性,不想让它动态添加属性怎么办?比如我们只允许对A的实例添加name和age属性。

​ 为了达到上述目的,Python允许在定义class的时候,定义一个__slots__变量,来限制该class的实例能添加的属性。

class A(object):
  __slots__ = ('age','name')
a = A()
a.name = 'xiaoming'
a.age = 10
a.id = 123456 #error  AttributeError: 'A' object has no attribute 'id'

由于id不在__slots__中,所以实例不能添加id属性。任何试图给实例添加一个其名不在__slots__中的属性都将触发AttributeError异常。

实现原理

__slots__中的变量是类属性,类型为数据描述符。

#!/usr/bin/python
# -*- coding: utf-8 -*-
class Foo(object):
  __slots__ = ('age','name')
  def __init__(self,age = 0):
    self.age = age

s = Foo.__dict__['age']
print s          #<member 'age' of 'Foo' objects>
print type(s)       #<type 'member_descriptor'>
'''证明为数据描述符'''
print '__get__' in dir(s) #True
print '__set__' in dir(s) #True

__slots__中的变量虽然是类属性,但是不同实例之间互不影响。因为描述符方法的一个参数为实例,建立一个实例和值的映射还是很简单的。如果不懂,建议看描述符 。

f1 = Foo(1)
f2 = Foo(2)
print f1.age,f2.age          #1,2
print Foo.__dict__['age'].__get__(f1) #1
print Foo.__dict__['age'].__get__(f2) #2

__slots__的好处

如果类没有定义__slots__ ,该类的实例会有__dict__属性,通过__dict__可修改,删除,增加实例属性。

如果类定义了__slots__,该类的实例不会有__dict__属性。实例中的__dict__属性是非常耗内存的,当创建上百万个实例的时候,所有实例的__dict__会占用一块很大的内存。没有了__dict__的实例也就不能动态添加属性,只需分配固定的空间来存储已知的属性。因此使用__slots__的类能节省一部分内存开销。

对于不需要动态添加属性的类来说,应使用__slots__。

注意:不用过早的使用这个方法,它不利于代码维护,当实例很多(上千万)时,这种优化才有明显的效果。在实际使用中,__slots__从未被当作一种安全的特性来使用,它是对内存和执行速度的一种性能优化。使用__slots__的类的实例不再使用字典来存储实例属性,而是使用基于数组的一种更加紧凑的数据结构,所以当实例很多时,使用__slots__可以显著减少内存占用和执行时间。

class A(object):
  pass

class B(object):
  __slots__ = ('age','name')

a = A()
b = B()

没有__slots__的类和实例

print a.__dict__ #{}
print A.__dict__ 
'''
{'__dict__': <attribute '__dict__' of 'A' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
'''

有__slots__的类和实例

print b.__dict__ #AttributeError: 'B' object has no attribute '__dict__'
print B.__dict__
'''
{'age': <member 'age' of 'B' objects>, '__module__': '__main__', '__doc__': None, '__slots__': ('age', 'name'), 'name': <member 'name' of 'B' objects>}
'''

使用定义__slots__的类的注意事项

class Foo(object):
  __slots__ = ('age','name')

1.__slots__仅对当前类起作用,对子类是不起作用的,除非在子类中也定义__slots__,这样,子类允许定义的属性就是自身的__slots__加上父类的__slots__。

class F1(Foo):
  pass

class F2(Foo):
  __slots__ = ()

f1,f2 = F1(),F2()
f1.a = 1
f2.a = 1    #AttributeError: 'F2' object has no attribute 'a'
f2.age = 1

2.如果实例未给__slots__中的变量赋值,该实例不能使用__slots__中的变量。

f = Foo()
print f.age  #AttributeError: age
f.age = 1
print f.age  #1

3.实例将不再拥有__dict__,但是类还是拥有__dict__属性的,所以还是可以给类增加类属性的;

f = Foo()
Foo.xx = 1
print f.xx   #1

4.定义了__slots__后,如果__slots__中的变量为类变量,该变量对于该类的实例来说是只读的。如果想修改的话,可以通过类来修改。

class Foo(object):
  __slots__ = ('age','name')
  age = 10
  def __init__(self):
    self.name = 'xiaoming'
f = Foo()
print f.name     #'xiaoming'
print f.age     #10
f.name = 'xiaohong' 

#f.age = 12     #AttributeError: 'Foo' object attribute 'age' is read-only

Foo.age = 12     #正确
print f.name     #'xiaohong'
print f.age     #12


#del f.age      #AttributeError: 'Foo' object attribute 'age' is read-only


#del f.name 调用的是描述符方法__delete__,应该是将描述符中存储的实例与值的映射删除了

del f.name      #实例属性的删除还是可以的,但是删除的并不是类字典中的name属性
print f.name     #AttributeError: name

del Foo.age     #通过类来删除类属性还是可以的,不过这样会影响该类的所有实例
print f.age     #AttributeError: 'Foo' object has no attribute 'age'

原因不知道…有知道的大神求指导…

参考网址
1.http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/0013868200605560b1bd3c660bf494282ede59fee17e781000
2.http://www.jianshu.com/p/ef1797577f71
3.http://www.jianshu.com/p/82ce2151d73b
4.http://blog.csdn.net/lis_12/article/details/53453665

到此这篇关于Python __slots__的使用方法的文章就介绍到这了,更多相关Python __slots__内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
对于Python编程中一些重用与缩减的建议
Apr 14 Python
python语言使用技巧分享
May 31 Python
Mac中升级Python2.7到Python3.5步骤详解
Apr 27 Python
Python实现购物车购物小程序
Apr 18 Python
python 判断文件还是文件夹的简单实例
Jun 10 Python
Django使用模板后无法找到静态资源文件问题解决
Jul 19 Python
python cv2读取rtsp实时码流按时生成连续视频文件方式
Dec 25 Python
keras打印loss对权重的导数方式
Jun 10 Python
Python实现淘宝秒杀功能的示例代码
Jan 19 Python
Python解析m3u8拼接下载mp4视频文件的示例代码
Mar 03 Python
能让Python提速超40倍的神器Cython详解
Jun 24 Python
微信小程序调用python模型
Apr 21 Python
Python descriptor(描述符)的实现
Nov 15 #Python
基于OpenCV的网络实时视频流传输的实现
Nov 15 #Python
彻底解决Python包下载慢问题
Nov 15 #Python
Python eval函数原理及用法解析
Nov 14 #Python
Django怎么在admin后台注册数据库表
Nov 14 #Python
通过实例解析python and和or使用方法
Nov 14 #Python
Python高并发和多线程有什么关系
Nov 14 #Python
You might like
一个阿拉伯数字转中文数字的函数
2006/10/09 PHP
Discuz!5的PHP代码高亮显示插件(黑暗中的舞者更新)
2007/01/29 PHP
discuz7 phpMysql操作类
2009/06/21 PHP
深入php define()函数以及defined()函数的用法详解
2013/06/05 PHP
体育彩票排列三组选三算法分享
2014/03/07 PHP
php生成百度sitemap站点地图类函数实例
2014/10/17 PHP
php使用MySQL保存session会话的方法
2015/06/26 PHP
php封装的page分页类完整实例
2016/10/18 PHP
PHP不使用内置函数实现字符串转整型的方法示例
2017/07/03 PHP
无阻塞加载脚本分析[全]
2011/01/20 Javascript
用JavaScript仿PS里的羽化效果代码
2011/12/20 Javascript
jquery使用ul模拟select实现表单美化的方法
2015/08/18 Javascript
JavaScript学习笔记整理之引用类型
2016/01/22 Javascript
javascript基础知识分享之类与函数化
2016/02/13 Javascript
Javascript 数组去重的方法(四种)详解及实例代码
2016/11/24 Javascript
JS定时器用法分析【时钟与菜单中的应用】
2016/12/21 Javascript
基于vue实现分页/翻页组件paginator示例
2017/03/09 Javascript
原生js实现省市区三级联动代码分享
2018/02/12 Javascript
使用Angular CLI进行单元测试和E2E测试的方法
2018/03/24 Javascript
Vue不能观察到数组length的变化
2018/06/08 Javascript
[05:46]2018完美盛典-《同梦共竞》
2018/12/17 DOTA
实例说明Python中比较运算符的使用
2015/05/13 Python
python爬虫入门教程--快速理解HTTP协议(一)
2017/05/25 Python
react+django清除浏览器缓存的几种方法小结
2019/07/17 Python
django 中使用DateTime常用的时间查询方式
2019/12/03 Python
Python模块常用四种安装方式
2020/10/20 Python
沪江旗下的海量优质课程平台:沪江网校
2017/11/07 全球购物
澳大利亚最早和最古老的巨型游戏专家:Yardgames
2020/02/20 全球购物
垃圾回收的优点和原理
2014/05/16 面试题
会计学个人自荐信模板
2013/12/13 职场文书
最新大学生创业计划书写作攻略
2014/04/02 职场文书
小学生演讲稿大全
2014/04/25 职场文书
幼儿园课题实施方案
2014/05/14 职场文书
后进基层党组织整改方案
2014/10/25 职场文书
暑期社会实践新闻稿
2015/07/17 职场文书
Ajax实现三级联动效果
2021/10/05 Javascript