0%

python是否会重复使用重复的计算结果?

❓ 如果我有一个希望在Python中求值的表达式,例如下面的代码片段中的r表达式,那么Python解释器会不会很聪明并且可以重用x + y + z子结果,或者只求它两次? 我也想知道这个问题的答案是否与编译语言相同,例如C。

1
2
3
4
x = 1
y = 2
z = 3
r = (x+y+z+1) + (x+y+z+2)

✔️ 您可以使用dis.dis进行检查。输出为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2           0 LOAD_CONST               0 (1)
2 STORE_NAME 0 (x)

3 4 LOAD_CONST 1 (2)
6 STORE_NAME 1 (y)

4 8 LOAD_CONST 2 (3)
10 STORE_NAME 2 (z)

5 12 LOAD_NAME 0 (x)
14 LOAD_NAME 1 (y)
16 BINARY_ADD
18 LOAD_NAME 2 (z)
20 BINARY_ADD
22 LOAD_CONST 0 (1)
24 BINARY_ADD
26 LOAD_NAME 0 (x)
28 LOAD_NAME 1 (y)
30 BINARY_ADD
32 LOAD_NAME 2 (z)
34 BINARY_ADD
36 LOAD_CONST 1 (2)
38 BINARY_ADD
40 BINARY_ADD
42 STORE_NAME 3 (r)
44 LOAD_CONST 3 (None)
46 RETURN_VALUE

因此,它不会将表达式的结果缓存在括号中。尽管对于这种特定情况,它是可能的,但通常不会,因为自定义类可以定义__add__(或任何其他二进制操作)来修改自己。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Foo:
def __init__(self, value):
self.value = value

def __add__(self, other):
self.value += 1
return self.value + other

x = Foo(1)
y = 2
z = 3
print(x + y + z + 1) # prints 8
print(x + y + z + 1) # prints 9

如果您想要缓存结果,则可以通过例如functools.lru_cache来实现。另一方面,如以下示例所示,编译器将执行constant folding:

1
2
3
4
5
6
7
8
9
10
11
>>> import dis
>>> dis.dis("x = 'abc' * 5")
1 0 LOAD_CONST 0 ('abcabcabcabcabc')
2 STORE_NAME 0 (x)
4 LOAD_CONST 1 (None)
6 RETURN_VALUE
>>> dis.dis("x = 1 + 2 + 3 + 4")
1 0 LOAD_CONST 0 (10)
2 STORE_NAME 0 (x)
4 LOAD_CONST 1 (None)
6 RETURN_VALUE