Welcome 微信登录

首页 / 操作系统 / Linux / Python中类的__slots__属性

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

用法

__slots__可以被设置成属性名称的字符串,可遍历的对象或者序列。
之前在看odoo源码缓存相关的内容时,看到过下面这个例子:class ormcache_counter(object):""" Statistic counters for cache entries. """__slots__ = ["hit", "miss", "err"]def __init__(self):self.hit = 0self.miss = 0self.err = 0@propertydef ratio(self):return 100.0 * self.hit / (self.hit + self.miss or 1)这里创建了一个用来记录每个方法缓存情况的对象,因为对于需要每个缓存的方法,都会创建一个该实例来记录缓存的状况(比如缓存用到或没用的次数等),所以为了节省内存加快访问速度这里指定了该对象拥有的三个属性。

测试

访问速度测试

timeit是python一个用来简单测试运行时间的模块,详细可参见官方文档。# In Python2.7# test1.pyimport timeitclass Foo(object): __slots__ = "foo",class Bar(object): passslotted = Foo()not_slotted = Bar()def get_set_delete_fn(obj):def get_set_delete():obj.foo = "foo"obj.foodel obj.fooreturn get_set_delete# In REPL>>> from test1 import *>>> min(timeit.repeat(get_set_delete_fn(not_slotted)))min(timeit.repeat(get_set_delete_fn(not_slotted)))0.24305510520935059>>> min(timeit.repeat(get_set_delete_fn(slotted)))min(timeit.repeat(get_set_delete_fn(slotted)))0.21287798881530762可以看见,使用__slots__的对象有更快的访问速度,虽然在python2.7中差别没有在python3中那么明显

内存占用参考

关于内存占用情况的测试我还没测,但可以参考 stackoverflow上的测试,我这里机(无)智(耻)地取个结果:# 单位 bytesattrs__slots__no slots declared + __dict__none 1664 (+ 280 if __dict__ referenced)one5664 + 280two6464 + 280six9664 + 10482222464 + 3352可以明显看到内存占用减少的情况。

注意事项

__dict__可以理解成类里面存储属性的字典,
  1. 当一个类A继承自一个没有定义__slots__的类B时,A是有__dict__属性,这是再定义__slots__属性没有意义, 不能达到限制内存的作用
  2. 当尝试给一个定义了__slots__的类,而没有定义__dict__的类设置不在__slots__指定的那些属性时,会导致一个AttributeError
    其它注意请参照文档
本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-12/137776.htm