Python中的链式比较实际上是如何工作的?

2024-04-23 07:04:06 发布

您现在位置:Python中文网/ 问答频道 /正文

Python Doc for Comparisons上写着:

Comparisons can be chained arbitrarily, e.g., x < y <= z is equivalent to x < y and y <= z, except that y is evaluated only once (but in both cases z is not evaluated at all when x < y is found to be false).

这些问题/答案让我们对这种用法有了更多的了解:

比如(人为的例子):

if 1 < input("Value:") < 10: print "Is greater than 1 and less than 10"

只要求输入一次。这是有道理的。还有这个:

^{pr2}$

如果Val1在1&10之间,只要求Val2,并且只打印“woo!”如果Val2也在10到20之间(证明它们可以“任意链接”)。这也有道理。在

但我仍然很好奇这是如何在lexer/parser/compiler(或其他)级别实现/解释的。在

上面的第一个例子基本上是这样实现的:

x = input("Value:")
1 < x and x < 10: print "Is between 1 and 10"

其中x真的只存在于这些比较中(实际上是未命名的)?或者它会使比较运算符返回布尔结果和右操作数的求值(用于进一步比较)或类似的东西?在

将分析扩展到第二个例子使我相信它使用了类似于未命名的中间结果(如果有术语的话,有人会告诉我),因为它在进行比较之前没有计算所有的操作数。在


Tags: andtoinonlyforinputisvalue
1条回答
网友
1楼 · 发布于 2024-04-23 07:04:06

您可以简单地让Python告诉您使用^{} 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使用堆栈,^{} bytecode使用堆栈上的项(input全局和{}字符串)用一个参数调用函数,用函数调用的结果替换堆栈上的这两个项。在函数调用之前,常量1被加载到堆栈中。在

所以在调用input时,堆栈看起来像:

^{pr2}$

并且^{}复制顶部值,在rotating the top three stack值之前到达:

1
input_result
input_result

和一个COMPARE_OP来用<测试前两个项目,用结果替换前两个项目。在

如果结果是False,则^{} bytecode跳到27,它将顶部的False与剩余的input_result一起旋转,用POP_TOP清除掉,然后返回剩余的False顶部值作为结果。在

但是,如果结果True,则该值由JUMP_IF_FALSE_OR_POP字节码弹出堆栈,并在其所在位置将10值加载到顶部,我们得到:

10    
input_result

然后进行另一个比较并返回。在

总之,Python基本上是这样做的:

stack_1 = stack_2 = input('Value:')
if 1 < stack_1:
    result = False
else:
    result = stack_2 < 10

再次清除stack_*值。在

然后,堆栈将保存未命名的中间结果进行比较

相关问题 更多 >