这是一个简单的示例:
>>> def foo():
... if True:
... return 'yes'
...
>>> import dis
>>> dis.dis(foo)
3 0 LOAD_CONST 1 ('yes')
2 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
为什么这里没有关于 if 语句的字节码?它只是直接返回值。
在 Python 3 中,True不能被覆盖,所以 Python 被允许“优化”它并假设它True总是正确的。
由于历史原因,Python 2 没有True作为常量/关键字,因此该语言不允许对此进行优化:
Python 2.7.16 (default, May 8 2021, 11:48:02)
[GCC Apple LLVM 12.0.5 (clang-1205.0.19.59.6) [+internal-os, ptrauth-isa=deploy on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> def foo():
... if True:
... return 'yes'
...
>>> import dis
>>> dis.dis(foo)
2 0 LOAD_GLOBAL 0 (True)
3 POP_JUMP_IF_FALSE 10
3 6 LOAD_CONST 1 ('yes')
9 RETURN_VALUE
>> 10 LOAD_CONST 0 (None)
13 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
因此,从历史上看,在 Python 2 中,您可以(即使您永远不应该)设置True = 213或什至True = 0(或True = False)并弄乱您的程序逻辑:
>>> True = 0
>>> print(foo())
None
>>> True = 1
>>> print(foo())
yes
Run Code Online (Sandbox Code Playgroud)
在 Python 3 中,这是不可能的:
Python 3.9.5 (default, May 4 2021, 03:36:27)
[Clang 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> True = 213
File "<stdin>", line 1
True = 213
^
SyntaxError: cannot assign to True
Run Code Online (Sandbox Code Playgroud)
请注意,这if True是一种特殊情况,因为 Python 3 无法优化其他重言式(目前):
>>> def foo():
... if 3 == 3:
... return 'yes'
...
>>> import dis
>>> dis.dis(foo)
2 0 LOAD_CONST 1 (3)
2 LOAD_CONST 1 (3)
4 COMPARE_OP 2 (==)
6 POP_JUMP_IF_FALSE 12
3 8 LOAD_CONST 2 ('yes')
10 RETURN_VALUE
>> 12 LOAD_CONST 0 (None)
14 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
请注意,这是特定于实现的(CPython),在 PyPy 3 中又略有不同;它可以确定if True始终是True,但随后也在return None函数末尾为隐式生成字节码(永远不会被执行):
Python 3.7.10 (51efa818fd9b24f625078c65e8e2f6a5ac24d572, Apr 08 2021, 17:43:00)
[PyPy 7.3.4 with GCC Apple LLVM 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>> def foo():
.... if True:
.... return 'yes'
....
>>>> import dis
>>>> dis.dis(foo)
3 0 LOAD_CONST 1 ('yes')
2 RETURN_VALUE
4 LOAD_CONST 0 (None)
6 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
再次为了完整起见,不允许使用 Python 2.7 语义的 PyPy 优化掉True,因为它可以设置为其他内容(此处隐式代码return None是正确的,因为它可能会根据您设置的内容True执行):
Python 2.7.18 (63df5ef41012b07fa6f9eaba93f05de0eb540f88, Apr 08 2021, 15:53:40)
[PyPy 7.3.4 with GCC Apple LLVM 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>> def foo():
.... if True:
.... return 'yes'
....
>>>> import dis
>>>> dis.dis(foo)
2 0 LOAD_GLOBAL 0 (True)
3 POP_JUMP_IF_FALSE 10
3 6 LOAD_CONST 1 ('yes')
9 RETURN_VALUE
>> 10 LOAD_CONST 0 (None)
13 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
它是如何在 CPython 中实现的
优化在CPython的3在实施optimize_basic_block()中Python/compile.c,截至本文写作这一行(“删除LOAD_CONST常量;条件跳转”)做了优化。换句话说,编译器生成这样的操作码:
LOAD_CONST ... (True)
POP_JUMP_IF_FALSE x
LOAD_CONST ... ('yes')
RETURN_VALUE
x LOAD_CONST ... (None)
RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
因此,如果它看到 aLOAD_CONST后跟 a POP_JUMP_IF_FALSE,并且可以证明该常量True在编译时,它将删除 theLOAD_CONST并将 thePOP_JUMP_IF_FALSE变成 aJUMP_ABSOLUTE或变成 a NOP,这取决于计算的布尔值(这里它将变成 a NOP) :
NOP
NOP
LOAD_CONST ... ('yes')
RETURN_VALUE
x LOAD_CONST ... (None)
RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
进一步的步骤 ( clean_basic_block()) 然后将删除 NOP(无操作),并且可能额外的步骤会找出之后的代码RETURN_VALUE已死并删除它。