比较可以任意链接,例如,
x < y <= z
等同于x < y and y <= z
,但y
仅评估一次(但在两种情况下z
都未评估所有x < y
被发现为假的时候。
这些SO问题/答案更能说明这种用法:
所以像(人为的例子):
if 1 < input("Value:") < 10: print "Is greater than 1 and less than 10"
只要求输入一次。这是有道理的。这个:
if 1 < input("Val1:") < 10 < input("Val2:") < 20: print "woo!"
仅询问Val2
,如果 Val1
介于1&amp;之间10只打印“呜!” 如果 Val2
也在10到20之间(证明它们可以“任意链接”)。这也是有道理的。
但我仍然很好奇这是如何在lexer / parser / compiler(或其他)级别实际实现/解释的。
上面的第一个例子基本上是这样实现的:
x = input("Value:")
1 < x and x < 10: print "Is between 1 and 10"
这些比较中x
实际上只存在(并且实际上基本上未命名)?或者它是否以某种方式使比较运算符返回布尔结果和右操作数的评估(用于进一步比较)或类似的东西?
将分析扩展到第二个例子让我相信它正在使用类似未命名的中间结果(有人教育我,如果有一个术语),因为在进行比较之前它不会评估所有的操作数。
答案 0 :(得分:10)
您可以简单地让Python告诉您使用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使用堆栈; CALL_FUNCTION
bytecode使用堆栈上的项(input
全局和'Value:'
字符串)来调用带有一个参数的函数,用函数的结果替换堆栈中的这两个项呼叫。在函数调用之前,常量1
已加载到堆栈中。
因此,在调用input
时,堆栈看起来像:
input_result
1
和DUP_TOP
重复最高值,在rotating the top three stack值到达之前:
1
input_result
input_result
和COMPARE_OP
使用<
测试前两项,用结果替换前两项。
如果结果为False
,JUMP_IF_FALSE_OR_POP
bytecode会跳转到27,这会将False
旋转到剩余的input_result
上,以清除{{1}然后返回剩余的POP_TOP
最高值作为结果。
但是,如果结果为False
,那么True
字节码会在堆栈中弹出该值,并且JUMP_IF_FALSE_OR_POP
值被加载到顶部,我们得到:
10
进行另一次比较并返回。
总之,基本上Python就是这样做的:
10
input_result
再次清除stack_1 = stack_2 = input('Value:')
if 1 < stack_1:
result = False
else:
result = stack_2 < 10
值。
然后,堆栈保存未命名的中间结果以进行比较