Python编程是个什么鬼?
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.
你也许感兴趣的:
- 程序员视频:理工男的磨刀石
- 程序员视频:来自linux程序员的消息
- 程序员视频:新手程序员是这样使用开发工具的
- 程序员视频:论搜索算法选择的重要性
- 趣视频:软件需求说明书
- 幽默视频:给新来的程序员写的代码做审查
- 大开眼界:“根据手机壳换APP颜色”不过是小意思【视频】
- 重看”Linus Torvalds on Git”视频
- 程序员搞笑视频:PHP=拍黄片
- 程序员搞笑视频:这都不会,你是程序员吗?!
你对本文的反应是: