转自:http://blog.csdn.net/sxingming/article/details/52892640

python中的new-style class要求继承Python中的一个内建类型,一般继承object,也可以继承list或者dict等其他的内建类型。
在python新式类中,可以定义一个变量__slots__,它的作用是阻止在实例化类时为实例分配dict,

默认情况下每个类都会有一个dict,通过__dict__访问,这个dict维护了这个实例的所有属性,举例如下:

  1. class base(object):
  2. var=9 #类变量
  3. def __init__(self):
  4. pass
  5. b=base()
  6. print b.__dict__
  7. b.x=2 #添加实例变量
  8. print b.__dict__

运行结果:
{ }
{'x': 2}
可见:实例的dict只保持实例的变量,对于类的属性是不保存的,类的属性包括变量和函数。
由于每次实例化一个类都要分配一个新的dict,因此存在空间的浪费,因此有了__slots__。
__slots__是一个元组,包括了当前能访问到的属性。
当定义了slots后,slots中定义的变量变成了类的描述符,相当于java,c++中的成员变量声明,
类的实例只能拥有slots中定义的变量,不能再增加新的变量。注意:定义了slots后,就不再有dict。如下:

  1. class base(object):
  2. __slots__=('x')
  3. var=8
  4. def __init__(self):
  5. pass
  6. b=base()
  7. b.x=88 #添加实例变量
  8. print b.x
  9. #b.y=99 #无法添加slots之外的变量 (AttributeError: 'base' object has no attribute 'y')
  10. #print b.__dict__ #定义了__slots__后,就不再有__dict__ (AttributeError: 'base' object has no attribute '__dict__')

运行结果:
88
如果类变量与slots中的变量同名,则该变量被设置为readonly!!!如下:

  1. class base(object):
  2. __slots__=('y')
  3. y=22 # y是类变量,y与__slots__中的变量同名
  4. var=11
  5. def __init__(self):
  6. pass
  7. b=base()
  8. print b.y
  9. print base.y
  10. #b.y=66 #AttributeError: 'base' object attribute 'y' is read-only

运行结果:
22
22
Python是一门动态语言,可以在运行过程中,修改实例的属性和增删方法。一般,任何类的实例包含一个字典__dict__,
Python通过这个字典可以将任意属性绑定到实例上。有时候我们只想使用固定的属性,而不想任意绑定属性,
这时候我们可以定义一个属性名称集合,只有在这个集合里的名称才可以绑定。__slots__就是完成这个功能的。

  1. class test_slots(object):
  2. __slots__='x','y'
  3. def printHello(self):
  4. print 'hello!'
  5. class test(object):
  6. def printHello(self):
  7. print 'hello'
  8. print dir(test_slots) #可以看到test_slots类结构里面包含__slots__,x,y
  9. print dir(test)#test类结构里包含__dict__
  10. print '**************************************'
  11. ts=test_slots()
  12. t=test()
  13. print dir(ts) #可以看到ts实例结构里面包含__slots__,x,y,不能任意绑定属性
  14. print dir(t) #t实例结构里包含__dict__,可以任意绑定属性
  15. print '***************************************'
  16. ts.x=11 #只能绑定__slots__名称集合里的属性
  17. t.x=12 #可以任意绑定属性
  18. print ts.x,t.x
  19. ts.y=22 #只能绑定__slots__名称集合里的属性
  20. t.y=23  #可以任意绑定属性
  21. print ts.y,t.y
  22. #ts.z=33 #无法绑定__slots__集合之外的属性(AttributeError: 'test_slots' object has no attribute 'z')
  23. t.z=34 #可以任意绑定属性
  24. print t.z

运行结果:
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'printHello', 'x', 'y']
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'printHello']
**************************************
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'printHello', 'x', 'y']
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'printHello']
***************************************
11 12
22 23
34

正如上面所说的,默认情况下,Python的新式类和经典类的实例都有一个dict来存储实例的属性。这在一般情况下还不错,而且非常灵活,
乃至在程序中可以随意设置新的属性。但是,对一些在”编译”前就知道有几个固定属性的小class来说,这个dict就有点浪费内存了。
当需要创建大量实例的时候,这个问题变得尤为突出。一种解决方法是在新式类中定义一个__slots__属性。
__slots__声明中包含若干实例变量,并为每个实例预留恰好足够的空间来保存每个变量;这样Python就不会再使用dict,从而节省空间。

【使用memory_profiler模块,memory_profiler模块是在逐行的基础上,测量代码的内存使用率。尽管如此,它可能使得你的代码运行的更慢。使用装饰器@profile来标记哪个函数被跟踪。】

下面,我们看一个例子:

  1. from  memory_profiler import profile
  2. class A(object): #没有定义__slots__属性
  3. def __init__(self,x):
  4. self.x=x
  5. @profile
  6. def main():
  7. f=[A(523825) for i in range(100000)]
  8. if __name__=='__main__':
  9. main()

运行结果,如下图:

第2列表示该行执行后Python解释器的内存使用情况,第3列表示该行代码执行前后的内存变化。
在没有定义__slots__属性的情况下,该代码共使用了20.8MiB内存。
从结果可以看出,内存使用是以MiB为单位衡量的,表示的mebibyte(1MiB = 1.05MB)

  1. from  memory_profiler import profile
  2. class A(object):#定义了__slots__属性
  3. __slots__=('x')
  4. def __init__(self,x):
  5. self.x=x
  6. @profile
  7. def main():
  8. f=[A(523825) for i in range(100000)]
  9. if __name__=='__main__':
  10. main()

运行结果,如下图:

可以看到,在定义了__slots__属性的情况下,该代码共使用了6.1MiB内存,比上面的20.8MiB节省了很多内存!
综上所述,在确定了类的属性固定的情况下,可以使用__slots__来优化内存。
提醒:不要贸然进行这个优化,把它用在所有地方。这种做法不利于代码维护,而且只有生成数以千计的实例的时候才会有明显效果。

python __slots__ 详解(上篇)的更多相关文章

  1. Python Collections详解

    Python Collections详解 collections模块在内置数据结构(list.tuple.dict.set)的基础上,提供了几个额外的数据结构:ChainMap.Counter.deq ...

  2. Python闭包详解

    Python闭包详解 1 快速预览 以下是一段简单的闭包代码示例: def foo(): m=3 n=5 def bar(): a=4 return m+n+a return bar >> ...

  3. [转] Python Traceback详解

    追莫名其妙的bugs利器-mark- 转自:https://www.jianshu.com/p/a8cb5375171a   Python Traceback详解   刚接触Python的时候,简单的 ...

  4. python 数据类型详解

    python数据类型详解 参考网址:http://www.cnblogs.com/linjiqin/p/3608541.html 目录1.字符串2.布尔类型3.整数4.浮点数5.数字6.列表7.元组8 ...

  5. Python 递归函数 详解

    Python 递归函数 详解   在函数内调用当前函数本身的函数就是递归函数   下面是一个递归函数的实例: 第一次接触递归函数的人,都会被它调用本身而搞得晕头转向,而且看上面的函数调用,得到的结果会 ...

  6. python线程详解

    #线程状态 #线程同步(锁)#多线程的优势在于可以同时运行多个任务,至少感觉起来是这样,但是当线程需要共享数据时,可能存在数据不同步的问题. #threading模块#常用方法:'''threadin ...

  7. python数据类型详解(全面)

    python数据类型详解 目录1.字符串2.布尔类型3.整数4.浮点数5.数字6.列表7.元组8.字典9.日期 1.字符串1.1.如何在Python中使用字符串a.使用单引号(')用单引号括起来表示字 ...

  8. python生成器详解

    1. 生成器 利用迭代器(迭代器详解python迭代器详解),我们可以在每次迭代获取数据(通过next()方法)时按照特定的规律进行生成.但是我们在实现一个迭代器时,关于当前迭代到的状态需要我们自己记 ...

  9. 转 python数据类型详解

    python数据类型详解 目录 1.字符串 2.布尔类型 3.整数 4.浮点数 5.数字 6.列表 7.元组 8.字典 9.日期 1.字符串 1.1.如何在Python中使用字符串 a.使用单引号(' ...

随机推荐

  1. NTKO在线office控件使用实例

    目录 1. NTKO在线office控件使用实例 1.1. 基础介绍 1.2. 基本原理 1.3. 实例 1.3.1. 打开.保存部分代码 1.3.2. 动态设值 1. NTKO在线office控件使 ...

  2. visio中怎样画线条或箭头

    1.在"画图"工具栏上,单击"铅笔"工具  或"线条"工具  . (凝视   假设看不到"画图"工具栏,请单击" ...

  3. 【block第四篇】实现

    -------------------------------------------欢迎查看block连载博客[专栏]--------------------------------------[b ...

  4. QlikView格式化某一个单元格

    QlikView中能够创建透视表和垂直表,或者一般的Table.假如有的时候须要某一个单元格的样式和其它单元格不一样.颜色或者边框宽度等.能够通过下面方式实现: 工具栏里面有个button叫:Desi ...

  5. AVAudioSessionCategory的选择

    AVAudioSessionCategoryAmbient 或 kAudioSessionCategory_AmbientSound --用于非以语音为主的应用,使用这个category的应用会随着静 ...

  6. dumpdecrypted进行砸壳

    1.下载源码git clone git://github.com/stefanesser/dumpdecrypted/ 2.进行编译生成 dumpdecrypted.dylibmake 3.将dump ...

  7. easyUI 动态添加窗体

    有一张页面A,在页面开头引用了jquery.easyUI.min.js. 现在想达到这么一种效果,点击页面A的一个按钮,弹出一个easyUI窗体.因为想分模块的原因,这个窗体对应的是另一张页面B.在点 ...

  8. JavaScript基础 -- 定时器

     js 定时器有以下两个方法: setInterval() :按照指定的周期(以毫秒计)来调用函数或计算表达式.方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭. set ...

  9. go1

    关键字: break default func interface select case defer go map struct chan else goto package switch cons ...

  10. ResolveUrl in external JavaScript file in asp.net project

    https://stackoverflow.com/questions/11263425/page-resolveurl-is-not-working-in-javascript The proble ...