问题描述
比较可以任意链接,例如,x 等价于
x ,除了
y
只计算一次(但在这两种情况下,z
在 x 被发现是假的).
这些 SO 问题/答案对这种用法有更多的了解:
所以像(人为的例子):
if 1
只要求输入一次.这是有道理的.还有这个:
if 1
仅要求 Val2
if Val1
介于 1 &10 并且只打印woo!"if Val2
也在 10 到 20 之间(证明它们可以任意链接").这也有道理.
但我仍然很好奇这是如何在词法分析器/解析器/编译器(或其他)级别实际实现/解释的.
上面的第一个例子基本上是这样实现的:
x = input("值:")1
对于那些比较,x
真的只存在(实际上基本上没有命名)?或者它是否以某种方式使比较运算符返回布尔结果和正确操作数的评估(用于进一步比较)或类似的东西?
将分析扩展到第二个示例让我相信它使用了类似未命名的中间结果(如果有术语的话有人教我),因为它在进行比较之前不会评估所有操作数.
您可以简单地让 Python 告诉您使用 dis
模块:
Python 使用堆栈;CALL_FUNCTION
字节码使用项目堆栈(input
全局和 'Value:'
字符串)以调用带有一个参数的函数,用函数的结果替换堆栈中的这两项称呼.在函数调用之前,常量 1
已加载到堆栈中.
所以当 input
被调用时,堆栈看起来像:
input_result1
和 DUP_TOP
重复在旋转前三个堆栈值到达之前的最高值在:
1输入结果输入结果
和一个 COMPARE_OP
用 <
测试前两项,用结果替换前两项.
如果结果是False
JUMP_IF_FALSE_OR_POP
字节码 跳转到 27,这会将 False
与剩余的 input_result
一起旋转到顶部,以使用 清除它POP_TOP
,然后返回剩余的 False
顶部值作为结果.
如果结果为 True
,则该值由 JUMP_IF_FALSE_OR_POP
字节码从堆栈中弹出,并在其位置加载 10
值在顶部,我们得到:
10输入结果
进行另一次比较并返回.
总而言之,本质上 Python 就是这样做的:
stack_1 = stack_2 = input('Value:')如果 1
再次清除 stack_*
值.
然后,堆栈保存未命名的中间结果以进行比较
The Python Doc for Comparisons says:
And these SO questions/answers shed some more light on such usage:
- Python comparison operators chaining/grouping left to right?
- What does "evaluated only once" mean for chained comparisons in Python?, in particular the currently-accepted answer
So something like (contrived example):
if 1 < input("Value:") < 10: print "Is greater than 1 and less than 10"
only asks for input once. This makes sense. And this:
if 1 < input("Val1:") < 10 < input("Val2:") < 20: print "woo!"
only asks for Val2
if Val1
is between 1 & 10 and only prints "woo!" if Val2
is also between 10 and 20 (proving they can be 'chained arbitrarily'). This also makes sense.
But I'm still curious how this is actually implemented/interpreted at the lexer/parser/compiler (or whatever) level.
Is the first example above basically implemented like this:
x = input("Value:")
1 < x and x < 10: print "Is between 1 and 10"
where x
really only exists (and is actually essentially unnamed) for those comparisons? Or does it somehow make the comparison operator return both the boolean result and the evaluation of the right operand (to be used for further comparison) or something like that?
Extending analysis to the second example leads me to believe it's using something like an unnamed intermediate result (someone educate me if there's a term for that) as it doesn't evaluate all the operands before doing the comparison.
You can simply let Python tell you what bytecode is produced with the dis
module:
>>> import dis
>>> def f(): return 1 < input("Value:") < 10
...
>>> dis.dis(f)
1 0 LOAD_CONST 1 (1)
3 LOAD_GLOBAL 0 (input)
6 LOAD_CONST 2 ('Value:')
9 CALL_FUNCTION 1
12 DUP_TOP
13 ROT_THREE
14 COMPARE_OP 0 (<)
17 JUMP_IF_FALSE_OR_POP 27
20 LOAD_CONST 3 (10)
23 COMPARE_OP 0 (<)
26 RETURN_VALUE
>> 27 ROT_TWO
28 POP_TOP
29 RETURN_VALUE
Python uses a stack; the CALL_FUNCTION
bytecode uses items on the stack (the input
global and the 'Value:'
string) to call a function with one argument, to replace those two items on the stack with the result of the function call. Before the function call, the the constant 1
was loaded on the stack.
So by the time input
was called the stack looks like:
input_result
1
and DUP_TOP
duplicates the top value, before rotating the top three stack values to arrive at:
1
input_result
input_result
and a COMPARE_OP
to test the top two items with <
, replacing the top two items with the result.
If that result was False
the JUMP_IF_FALSE_OR_POP
bytecode jumps over to 27, which rotates the False
on top with the remaining input_result
to clear that out with a POP_TOP
, to then return the remaining False
top value as the result.
If the result True
however, that value is popped of the stack by the JUMP_IF_FALSE_OR_POP
bytecode and in it's place the 10
value is loaded on top and we get:
10
input_result
and another comparison is made and returned instead.
In summary, essentially Python then does this:
stack_1 = stack_2 = input('Value:')
if 1 < stack_1:
result = False
else:
result = stack_2 < 10
with the stack_*
values cleared again.
The stack, then, holds the unnamed intermediate result to compare
这篇关于Python 中的链式比较实际上是如何工作的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!