为什么使用__slots__减慢这段代码?

问题描述:

Usage of __slots__?读到,在使用Python __slots__实际上可以节省时间。但是,当我试图找到使用datetime所花的时间时,结果是相反的。为什么使用__slots__减慢这段代码?

import datetime as t 

class A(): 
    def __init__(self,x,y): 
     self.x=x 
     self.y=y 
t1=t.datetime.now() 
a=A(1,2) 
t2=t.datetime.now() 
print(t2-t1) 

都给输出:0:00:00.000011 并采用插槽:

import datetime as t 

class A(): 
    __slots__ = 'x','y' 
    def __init__(self,x,y): 
     self.x=x 
     self.y=y 
t1=t.datetime.now() 
a=A(1,2) 
t2=t.datetime.now() 
print(t2-t1) 

都给输出:0:00:00.000021

使用插槽实际所花的时间。为什么我们需要使用__slots__呢?

+0

我注意,手动使用'datetime'这种方式不是用于定时码的推荐方法。有[用于计时代码片段的模块](https://docs.python.org/3/library/timeit.html)。 (正如答案中提到的)你必须多次重复短操作才能使任何事情接近有意义的结果。 –

  1. 你报的文章说使用插槽提供了更快的 属性访问 - 你测试的对象创建的时间,和 从来没有访问您的对象的属性。
  2. 测试单个操作不是统计意义 - 衡量的,比如100000次行动的时间。

__slots__可以节省时间(取决于Python版本),但这通常不是您使用它的原因。它真正节省的是内存。而不是每个实例相当大的__dict__。即使在现代PY3 64与密钥共享类型的字典,它仍然是一个关键的共享__dict__所在班级有一个实例属性,对对象结构本身的56个字节的最高96个字节。

使用__slots__,你消除对指针的__dict____weakref__属性的16个字节,并消除__dict__完全。

有关PY 3.5比较:

>>> class Foo: 
... def __init__(self, x): self.x = x 
... 
>>> sys.getsizeof(Foo(1)) + sys.getsizeof(Foo(1).__dict__) 
152 
>>> class Foo: 
... __slots__ = 'x', 
... def __init__(self, x): self.x = x 
... 
>>> sys.getsizeof(Foo(1)) # With __slots__, doesn't have __dict__ at all 
48 

这就是每实例超过100字节的节省;在Py2上(没有密钥共享词典),节省更多。

因此,并不是说__slots__通常速度更快(通常非常相似),但是如果您制作数百万个实例,则每个实例节省100 + B可能会帮助您将代码保存在缓存中,RAM等中。 ,而不是耗尽内存并分出一半数据进行交换。

至于对方的回答笔记,你从来没有真正进入你的属性,所以你没有标杆槽接可言,这就是为什么你看到的没有什么区别的。使用ipython3%%timeit魔法,我发现反复加载给定实例的属性x约15%的速度时,它的开槽(33.5 ns有__slots__与39.2纳秒无),但这只是在明显的微基准;它在真正的代码中很少重要(实际的工作不仅仅是属性查找)。重要的是,将内存使用量减少2-3倍是更大的收益。