python编译器可以用相同的参数优化两个连续的函数调用吗?



在我的代码中,我有这样一行:

result = len([x for x in otherList if func(x) is not None and func(x).weekday == 3])

写在for循环中,我只定义一个变量,如fx = func(x),然后使用它两次。但我更喜欢我的代码目前编写的方式,我只是担心由于func(x)可能是昂贵的,它将被求值两次。是否有一些相当简单的方法来知道编译器是否会优化这样的语句,并且只评估函数一次?

是否有一些合理简单的方法来知道编译器是否会优化这样的语句并且只评估函数一次?

是的,有,您可以查看生成的字节码:

import dis
otherList = []
def func(x):
pass
def main():
result = len([x for x in otherList if func(x) is not None and func(x).weekday == 3])
print(dis.dis(main))

输出:

Disassembly of <code object <listcomp> at 0x000002AAC3C743A0, file "test.py", line 8>:
8           0 BUILD_LIST               0
2 LOAD_FAST                0 (.0)
>>    4 FOR_ITER                34 (to 40)
6 STORE_FAST               1 (x)
8 LOAD_GLOBAL              0 (func)
10 LOAD_FAST                1 (x)
12 CALL_FUNCTION            1
14 LOAD_CONST               0 (None)
16 IS_OP                    1
18 POP_JUMP_IF_FALSE        4
20 LOAD_GLOBAL              0 (func)
22 LOAD_FAST                1 (x)
24 CALL_FUNCTION            1
26 LOAD_ATTR                1 (weekday)
28 LOAD_CONST               1 (3)
30 COMPARE_OP               2 (==)
32 POP_JUMP_IF_FALSE        4
34 LOAD_FAST                1 (x)
36 LIST_APPEND              2
38 JUMP_ABSOLUTE            4
>>   40 RETURN_VALUE
None

可以看到,函数被调用了两次。

解释器如何知道结果不会基于某些全局变量而改变?

如果你的函数的结果对于相同的参数永远不会改变,你可以考虑缓存它,例如通过使用lru_cache

正如@sahasrara62所指出的,您还可以使用"海象操作符"将函数调用的结果存储在表达式中。

可以使用赋值表达式:

result = len([x for x in otherList if (out:=func(x)) is not None and out.weekday == 3])

请注意,如果您只想要匹配的数量,使用sum可能更有效:

result = sum(1 for x in otherList if (out:=func(x)) is not None and out.weekday == 3)

最新更新