Python编程是个什么鬼?
I don’t know why this happens, but the Python interpreter gets very confused by this expression, even introducing a branch in an expression where only constants are loaded. This is really weird.
Here’s an image-to-text translation:
>>> True is not False
True
>>> True is not False is True
False
>>> (True is not False) is True
True
>>> True is not (False is True)
True
>>> True is (not False is True)
True
>>> True is not False is False
True
>>> wtf
True
The True is not False is False one surprised me.
This got me curious, so I looked a bit into it and disassembled the bytecode for these expressions.
TL;DR: The interpreter, for some reason, transforms True is not False is True into False is True, while also doing some other stuff and immediately discarding the results of this stuff.
Starting with:
def a():
return True is not (False is True)
Then running dis.dis(a) yields:
11 0 LOAD_CONST 1 (True)
2 LOAD_CONST 2 (False)
4 LOAD_CONST 1 (True)
6 COMPARE_OP 8 (is)
8 COMPARE_OP 9 (is not)
10 RETURN_VALUE
This is fairly straightforward. Looking at the state of the stack through this process:
| Opcode | Description | Stack |
|---|---|---|
0 LOAD_CONST 1 (True) |
Push True on top of the stack |
[True] |
2 LOAD_CONST 2 (False) |
Push False on top of the stack |
[False, True] |
4 LOAD_CONST 1 (True) |
Push True on top of the stack |
[True, False, True] |
6 COMPARE_OP 8 (is) |
Pop the top 2 elements off the stack, compare them using is and push the result on top of stack |
[False, True] |
8 COMPARE_OP 9 (is not) |
Pop the top 2 elements off the stack, compare them using is not and push the result on top of stack |
[True] |
10 RETURN_VALUE |
Return top of stack |
Pretty much what is expected. The results are very similar with True is (not False is True) and (True is not False) is True, so I won’t go into details. But when trying the same thing with True is not False is True, WTF?
9 0 LOAD_CONST 1 (True)
2 LOAD_CONST 2 (False)
4 DUP_TOP
6 ROT_THREE
8 COMPARE_OP 9 (is not)
10 JUMP_IF_FALSE_OR_POP 18
12 LOAD_CONST 1 (True)
14 COMPARE_OP 8 (is)
16 RETURN_VALUE
>> 18 ROT_TWO
20 POP_TOP
22 RETURN_VALUE
| Opcode | Description | Stack |
|---|---|---|
0 LOAD_CONST 1 (True) |
Push True on top of the stack |
[True] |
2 LOAD_CONST 2 (False) |
Push False on top of the stack |
[False, True] |
4 DUP_TOP |
Duplicate top of stack. WTF? | [False, False, True] |
6 ROT_THREE |
Lifts second and third stack item one position up, moves top down to position three | [False, True, False] |
8 COMPARE_OP 9 (is not) |
Pop the top 2 elements off the stack, compare them using is not and push the result on top of stack |
[True, False] |
10 JUMP_IF_FALSE_OR_POP 18 |
Jump to label 18 if top of stack is false. This will never happen. Otherwise, pop (discard) top of stack, which means the result of the previous comparison is discarded. The only thing left is the second constant loaded. This makes no sense | [False] |
12 LOAD_CONST 1 (True) |
Push True on top of the stack |
[True, False] |
14 COMPARE_OP 8 (is) |
Pop the top 2 elements off the stack, compare them using is and push the result on top of stack |
[False] |
16 RETURN_VALUE |
return top of stack | |
18 ROT_TWO |
Swap the 2 topmost elements of the stack. This will never happen, but I’m assuming the branch is somehow taken… | [False, True] |
20 POP_TOP |
Discard top of stack | [True] |
22 RETURN_VALUE |
return top of stack. This happens to be the corect value, but it is not the result of the comparisons in the code (the is not is ignored in this case) |
I don’t know why this happens, but the Python interpreter gets very confused by this expression, even introducing a branch in an expression where only constants are loaded. This is really weird.
Edit: I tried a few more variations of the expressions, it seems like adding parentheses almost anywhere puts the interpreter back on track, and changing the values of the booleans has no effect. Still no clue on why it fucks up, though.

你也许感兴趣的:
- Python 3.15 的 Windows x86-64 解释器有望提升 15% 运行速度
- 讨论:为什么Python能胜出?
- Python中的“冻结”字典
- Python的起源
- Reddit将评论后端从Python迁移至Go语言
- 首次探秘 Django 的新后台任务框架
- await 并非上下文切换:解析 Python 协程与任务的本质差异
- Python并非数据科学领域的理想语言(第二部分):语言特性
- Python并非数据科学领域的理想语言(第一部分):亲身经历
- 10 个提升 Python 代码运行速度的智能技巧

你对本文的反应是: