为什么有"slots"属性?

默认情况下,python对象队象的每个实例(instance)都会有一个字典来存储该实例的属性,这样做的好处在于运行时期每个对象可以任意设置新的属性。而相对应的坏处是,当创建成百上千个这样的实例的时候回很浪费内存。所以引入__slots__,用来指定实例只拥有固定的属性,因此python会给每个实例对象分配固定的内存空间,从而减少内存消耗。而且使用__slots__可以加快属性的访问。

用法

__slots__可以被设置成属性名称的字符串,可遍历的对象或者序列。

之前在看odoo源码缓存相关的内容时,看到过下面这个例子:

  1. class ormcache_counter(object):
  2. """ Statistic counters for cache entries. """
  3. __slots__ = ['hit', 'miss', 'err']
  4. def __init__(self):
  5. self.hit = 0
  6. self.miss = 0
  7. self.err = 0
  8. @property
  9. def ratio(self):
  10. return 100.0 * self.hit / (self.hit + self.miss or 1)

这里创建了一个用来记录每个方法缓存情况的对象,因为对于需要每个缓存的方法,都会创建一个该实例来记录缓存的状况(比如缓存用到或没用的次数等),所以为了节省内存加快访问速度这里指定了该对象拥有的三个属性。

测试

访问速度测试

timeit是python一个用来简单测试运行时间的模块,详细可参见官方文档

  1. # In Python2.7
  2. # test1.py
  3. import timeit
  4. class Foo(object): __slots__ = 'foo',
  5. class Bar(object): pass
  6. slotted = Foo()
  7. not_slotted = Bar()
  8. def get_set_delete_fn(obj):
  9. def get_set_delete():
  10. obj.foo = 'foo'
  11. obj.foo
  12. del obj.foo
  13. return get_set_delete
  14. # In REPL
  15. >>> from test1 import *
  16. >>> min(timeit.repeat(get_set_delete_fn(not_slotted)))
  17. min(timeit.repeat(get_set_delete_fn(not_slotted)))
  18. 0.24305510520935059
  19. >>> min(timeit.repeat(get_set_delete_fn(slotted)))
  20. min(timeit.repeat(get_set_delete_fn(slotted)))
  21. 0.21287798881530762

可以看见,使用__slots__的对象有更快的访问速度,虽然在python2.7中差别没有在python3中那么明显

内存占用参考

关于内存占用情况的测试我还没测,但可以参考 stackoverflow上的测试,我这里机(无)智(耻)地取个结果:

  1. # 单位 bytes
  2. attrs __slots__ no slots declared + __dict__
  3. none 16 64 (+ 280 if __dict__ referenced)
  4. one 56 64 + 280
  5. two 64 64 + 280
  6. six 96 64 + 1048
  7. 22 224 64 + 3352

可以明显看到内存占用减少的情况。

注意事项

__dict__可以理解成类里面存储属性的字典,

  1. 当一个类A继承自一个没有定义__slots__的类B时,A是有__dict__属性,这是再定义__slots__属性没有意义, 不能达到限制内存的作用
  2. 当尝试给一个定义了__slots__的类,而没有定义__dict__的类设置不在__slots__指定的那些属性时,会导致一个AttributeError

    其它注意请参照文档

类的__slots__属性的更多相关文章

  1. python类的__slots__属性、__del__属性、上下文(__enter__和__exit__)、

    常规情况下,类的属性字典是共享的,而实例的字典是独立的.如果一个类的属性较少,但是拥有很多的实例,这些实例的属性字典会占用较多的内存空间.对这样的类来说,为了节省内存空间,可以使用__slots__类 ...

  2. Python属性、方法和类管理系列之----__slots__属性

    一句话说明 __slots__是用来限制实例的属性的,__slots__可以规定实例是否应该有__dict__属性:__slots__不能限制类的属性. 只有__slots__列表内的这些变量名可赋值 ...

  3. Python 类的高级属性(可选)

    1.slots实例:限制类的实例有合法的属性集,只有__slots__属性列表中的属性才可能成为实例属性. 对象的实例通常没有一个属性字典,可以在__slots__列表中包含一个属性字典__dict_ ...

  4. __slots__属性

    使用__slots__时,子类不受影响 class Person(object): __slots__ = ("name","age") def __str__ ...

  5. Python的动态语言特性; __slots__属性

    python是动态语言 1. 动态语言的定义 动态编程语言 是 高级程序设计语言 的一个类别,在计算机科学领域已被广泛应用.它是一类 在运行时可以改变其结构的语言 :例如新的函数.对象.甚至代码可以被 ...

  6. id选择器、类选择器、属性选择器

    在网页编辑时,通常要对样式进行各种设置.我们借助CSS样式设计中的选择器,就能很好很方便的对它们进行管理和设置了. 今天,跟大家分享一下几个常用的选择器:id选择器.类选择器.属性选择器. id选择器 ...

  7. JS面向对象(3) -- Object类,静态属性,闭包,私有属性, call和apply的使用,继承的三种实现方法

    相关链接: JS面向对象(1) -- 简介,入门,系统常用类,自定义类,constructor,typeof,instanceof,对象在内存中的表现形式 JS面向对象(2) -- this的使用,对 ...

  8. 转载:java 中对类中的属性使用set/get方法的意义和用法

    经常看到有朋友提到类似:对类中的属性使用set/get方法的作用?理论的回答当然是封闭性之类的,但是这样对我们有什么作用呢?为什么要这样设计?我直接使用属性名来访问不是更直接,代码更简洁明了吗?下面我 ...

  9. java基础—继承题目:编写一个Animal类,具有属性:种类;具有功能:吃、睡。定义其子类Fish

    编写一个Animal类,具有属性:种类:具有功能:吃.睡.定义其子类Fish package zhongqiuzuoye; public class Animal { //属性 private Str ...

随机推荐

  1. Netbeans Platform 工程,免安装JDK

    使用Netbeans 6.8 创建了一个Netbeans Platform 工程,以Zip形式发布后, 按照以下操作,可 以在客户端免安装JDK: 1. 从已安装JDK的计算机中,提取JDK:eg. ...

  2. mysql show processlist 命令详解

    命令格式 SHOW [FULL] PROCESSLIST SHOW PROCESSLIST显示哪些线程正在运行.您也可以使用mysqladmin processlist语句得到此信息.如果您有SUPE ...

  3. HDU 5821 Ball (排序)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5821 有n个盒子,每个盒子最多装一个球. 现在进行m次操作,每次操作可以将l到r之间盒子的球任意交换. ...

  4. HDU 5438 Ponds (DFS,并查集)

    题意:给定一个图,然后让你把边数为1的结点删除,然后求连通块结点数为奇的权值和. 析:这个题要注意,如果删除一些结点后,又形成了新的边数为1的结点,也应该要删除,这是坑,其他的,先用并查集判一下环,然 ...

  5. javaScript中"=="和"==="运算符的区别

    相同点: 两个运算符均可用于比较两个值是否相等,可允许操作任意类型的操作数,如果操作数相等则返回true,否则返回false. 不同点: "==="运算符也称为严格相等运算符,它用 ...

  6. 关于 mobile sui a外链 老是出现加载失败的解决办法

    mobile sui 框架里面的a本身都绑了了一个ajax方法,ajax只能处理同域,跨域就会出现问题 ,所以mobile sui 中的a如果是外链的话就会出现加载失败的提示,这种明显的bug,让用户 ...

  7. C++学习之const整理总结

    1什么是const? (const类型)常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的.(但可以偷梁换柱进行更新) 2为什么引入const? const 推出的初始 ...

  8. 通过css代码使边框变圆角(ie9以下浏览器不支持)

    (从已经死了一次又一次终于挂掉的百度空间人工抢救出来的,发表日期2014-02-11) CSS代码: <style> #myDiv { border-radius: 4px; /*这句就是 ...

  9. Angular JS 使用的注意事项

    标签中ng-app,什么情况需要指定名称,什么时候又不需要呢? 1.ng-app="" <div ng-app="" ng-controller='myC ...

  10. Android Studio @Bind的用法,自动生成findViewById无需再实例化控件

    第一步:app 的build.gradle文件中添加 如下代码: compile 'com.jakewharton:butterknife:7.0.0' 点击Sync Now 同步下载第二步:安装插件 ...