Python 解释代码优化
考虑以下这段代码:
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
都是在加载 tdict
和 name
的值,所以答案似乎是否定的。