问题:Python是否会优化掉仅用作返回值的变量?
以下两个代码段之间是否有最终区别?首先为函数中的变量分配一个值,然后返回该变量。第二个函数只是直接返回值。
Python是否将它们转换为等效的字节码?是其中之一吗?
情况1:
def func():
a = 42
return a
情况2:
def func():
return 42
回答 0
不,不是。
CPython字节码的编译仅通过小型的猫眼优化器传递,该优化器仅用于基本优化(有关这些优化的更多信息,请参见测试套件中的test_peepholer.py)。
要查看实际发生的情况,请使用dis
*查看生成的指令。对于第一个函数,包含分配:
from dis import dis
dis(func)
2 0 LOAD_CONST 1 (42)
2 STORE_FAST 0 (a)
3 4 LOAD_FAST 0 (a)
6 RETURN_VALUE
而对于第二个功能:
dis(func2)
2 0 LOAD_CONST 1 (42)
2 RETURN_VALUE
第一个中使用了另外两个(快速)指令:fastlocals
当前执行帧数组中的值。然后,在两种情况下RETURN_VALUE
都执行a。所以,第二个是曾经如此轻微,由于执行需要更少的命令更快。
通常,请注意CPython编译器在执行的优化中是保守的。它并没有像其他编译器一样聪明(通常也有更多的信息可以使用)。除了显然是正确的以外,主要设计目标是:a)保持简单,并且b)尽可能快地进行编译,因此您甚至不会注意到存在编译阶段。
最后,您不应该为像这样的小问题而烦恼。速度的好处是微小的,恒定的,并且与解释Python事实所带来的开销相形见war。
* dis
是一个小的Python模块,可反汇编您的代码,您可以使用它查看VM将执行的Python字节码。
注意:正如@Jorn Vernee的评论中所述,这特定于Python的CPython实现。如果其他实现愿意的话,其他实现可能会进行更积极的优化,而CPython则不需要。
回答 1
两者基本上是相同的,除了在第一种情况下,对象42
只是简单地分配给名为的变量a
,换句话说,名称(即a
)是指值(即42
)。从某种意义上说,它从不复制任何数据,从技术上讲它不会做任何分配。
在return
ing期间,此命名绑定a
在第一种情况下返回,而对象42
在第二种情况下返回。
有关更多阅读,请参考Ned Batchelder的精彩文章