Python解释了代码优化

时间:2011-08-12 18:16:54

标签: python optimization interpreter

请考虑以下代码段:

dict [name] = 0
dict [name] += 1
dict [name] += 1

python解释器是否自动识别对字典值的重复引用并使用缓存的本地引用?,有点类似于C / C ++的别名优化,变成这样:

value = dict [name]
value = 0
value += 1
value += 1

显然,手动执行此操作并不是一件大事,但我很好奇是否真的有必要。任何见解,反馈等都表示赞赏。

4 个答案:

答案 0 :(得分:27)

您可以通过反汇编程序运行它来查找:

import dis

def test():
    name = 'test'
    tdict = {}
    tdict[name] = 0
    tdict[name] += 1
    tdict[name] += 1

dis.dis(test)

运行这个我们得到:

 13           0 LOAD_CONST               1 ('test')
              3 STORE_FAST               0 (name)

 14           6 BUILD_MAP                0
              9 STORE_FAST               1 (tdict)

 15          12 LOAD_CONST               2 (0)
             15 LOAD_FAST                1 (tdict)
             18 LOAD_FAST                0 (name)
             21 STORE_SUBSCR        

 16          22 LOAD_FAST                1 (tdict)
             25 LOAD_FAST                0 (name)
             28 DUP_TOPX                 2
             31 BINARY_SUBSCR       
             32 LOAD_CONST               3 (1)
             35 INPLACE_ADD         
             36 ROT_THREE           
             37 STORE_SUBSCR        

 17          38 LOAD_FAST                1 (tdict)
             41 LOAD_FAST                0 (name)
             44 DUP_TOPX                 2
             47 BINARY_SUBSCR       
             48 LOAD_CONST               3 (1)
             51 INPLACE_ADD         
             52 ROT_THREE           
             53 STORE_SUBSCR        
             54 LOAD_CONST               0 (None)
             57 RETURN_VALUE        

在这种情况下,LOAD_FAST每次尝试访问它以执行增量时tdictname的值都会加载,所以答案是似乎没有。

答案 1 :(得分:8)

仅通过检查代码就无法实现这种类型的优化。您的名字dict可能不是指本地字典,而是指实现__setitem__的用户定义对象,并且该方法必须被调用三次。在运行时,一个复杂的实现可以记录名称的实际值,并进行优化,但是在运行时不能在不破坏某些Python语义的情况下完成。

答案 2 :(得分:1)

不,因为那不起作用,你甚至用自己的代码证明了这一点 - 它实际上并不等同:

>>> a = {}
>>> name = 'x'
>>> a[name] = 0
>>> a[name] += 1
>>> a[name] += 1
>>> a[name] # ok no suprises so far
2
>>> a = {}
>>> a[name] = 0
>>> x = a[name] # x is now literally `0`, not some sort of reference to a[name]
>>> x
0
>>> x += 1
>>> x += 1
>>> a[name] # so this never changed
0
>>>

Python没有C-ish“引用”。您的想法仅适用于list等可变类型。这是Python的一个非常基本的属性,你可能应该忘记在编写Python时C教你的变量。

答案 3 :(得分:1)

将您的两个示例更改为以下内容:

#v1.py
di = {}
name = "hallo"
di[name] = 0
for i in range(2000000):
    di[name] += 1

#v2.py
di = {}
name = "hallo"
di[name] = 0
value = di[name]
for i in range(2000000):
    value += 1

您可以在以下测试中看到,v2更快,但pypy更快: - )

$ time python2.7 v1.py
real    0m0.788s
user    0m0.700s
sys     0m0.080s

$ time python2.7 v2.py
real    0m0.586s
user    0m0.490s
sys     0m0.090s

$ time pypy v1.py
real    0m0.203s
user    0m0.210s
sys     0m0.000s

$ time pypy v2.py
real    0m0.117s
user    0m0.080s
sys     0m0.030s

所以:为单个解释器优化代码并不好(我还没有测试过Jython ......),但是当someone优化解释器时它很棒......