用于比较的Python文档说:
可以任意链接比较,例如x < y <= z与等效x < y and y <= z,不同之处在于y比较仅被评估一次(但在两种情况下z都x < y被发现为假,则根本不评估)。
x < y <= z
x < y and y <= z
y
z
x < y
所以像(人为的例子):
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和10之间,并且仅打印“ woo!”。 if Val2也在10到20之间(证明它们可以“任意链接”)。这也是有道理的。
Val2
Val1
但是我仍然很好奇在lexer / parser / compiler(或其他)级别上如何实际实现/解释这一点。
上面的第一个示例基本上是这样实现的:
x = input("Value:") 1 < x and x < 10: print "Is between 1 and 10"
在x那些比较中真正存在的地方(实际上实际上是未命名的)?还是以某种方式使比较运算符同时返回布尔结果和正确操作数的评估(将用于进一步比较)还是类似的东西?
x
将分析扩展到第二个示例会使我相信,它使用的是诸如未命名中间结果之类的东西(如果有一个术语,有人会教我),因为它在进行比较之前不会评估所有操作数。
您可以简单地让Python告诉您dis模块产生了什么字节码:
dis
>>> 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字节码堆(上用途项目input的全球和'Value:'字符串)调用函数用一个参数,更换堆栈函数调用的结果在这两个项目。在函数调用之前,常量1已加载到堆栈中。
CALL_FUNCTION
input
'Value:'
1
因此,在input被调用时,堆栈看起来像:
input_result 1
并DUP_TOP复制最高值,然后旋转最高的三个堆栈值以得出:
DUP_TOP
1 input_result input_result
和COMPARE_OP用来测试前两项<,并用结果替换前两项。
COMPARE_OP
<
如果结果是字节码跳转到27,False则JUMP_IF_FALSE_OR_POP字节码将False顶部的剩余部分旋转到顶部,input_result用a清除该字节POP_TOP,然后返回剩余的False顶部值作为结果。
False
JUMP_IF_FALSE_OR_POP
input_result
POP_TOP
True但是,如果结果是该值,则该JUMP_IF_FALSE_OR_POP字节码会从堆栈中弹出该值,并将其放置10在顶部,我们得到:
True
10
10 input_result
然后进行另一个比较并返回。
综上所述,基本上,Python会这样做:
stack_1 = stack_2 = input('Value:') if 1 < stack_1: result = False else: result = stack_2 < 10
与stack_*值再次清除。
stack_*
然后,堆栈保存 未命名的中间结果 以进行比较