Python 解释代码优化

20 投票
4 回答
607 浏览
提问于 2025-04-16 23:30

考虑以下这段代码:

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

那么,Python解释器会不会自动识别对字典值的重复引用,并使用一个缓存的本地引用呢?这有点像C/C++中的别名优化,变成这样:

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

显然,手动这样做并不难,但我很好奇这是否真的有必要。任何见解、反馈等都很受欢迎。

4 个回答

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 语言那样的“引用”。你想的那种方式只适用于可变类型,比如 list(列表)。这是 Python 的一个非常基本的特性,所以在用 Python 编程时,你可能需要忘掉 C 语言教给你的关于变量的所有知识。

9

这种优化方式不能仅仅通过查看代码来实现。你用的名字 dict 可能并不是指Python自带的字典,而是一个用户自己定义的对象,这个对象实现了 __setitem__ 这个方法,而这个方法需要被调用三次。在程序运行时,一个复杂的实现可以注意到这个名字的实际值,并进行优化,但在程序运行之前是做不到的,这样会破坏一些Python的基本规则。

28

你可以通过反汇编工具来查看具体情况:

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 的值,所以答案似乎是否定的。

撰写回答