在这段代码中,当存在多个操作数时,如何使用“<=”和“<”?
在这段代码中,当存在多个操作数时,如何使用“<=”和“<”?
Python的比较运算符可以任意链式使用,例如,x < y <= z
等价于x < y and y <= z
,不同的是y
只会被计算一次(但在两种情况下,当x < y
为假时z
都不会被计算)。这些Stack Overflow的问题/答案对这种用法进行了更详细的解释:\n- [Python comparison operators chaining/grouping left to right?](https://stackoverflow.com/questions/25753474/python-comparison-operators-chaining-grouping-left-to-right)\n- [What does \"evaluated only once\" mean for chained comparisons in Python?](https://stackoverflow.com/questions/1664292/what-does-evaluated-only-once-mean-for-chained-comparisons-in-python),尤其是[当前被接受的答案](https://stackoverflow.com/questions/1664292/what-does-evaluated-only-once-mean-for-chained-comparisons-in-python/1664307#1664307)。\n因此,像下面这样的例子(构造的例子):\n
if 1 < input("Value:") < 10: print "Is greater than 1 and less than 10"
\n只会询问一次输入。这是有道理的。而且下面这个例子:\n
if 1 < input("Val1:") < 10 < input("Val2:") < 20: print "woo!"
\n只有在Val1
在1到10之间时才会询问Val2
,只有当Val2
也在10到20之间时才会打印\"woo!\"(证明它们可以任意链式使用)。这也是有道理的。\n但我还是想知道在词法分析器/解析器/编译器(或其他级别)中如何实际实现/解释这个问题。\n上面的第一个例子是否基本上是这样实现的:\n
x = input("Value:") 1 < x and x < 10: print "Is between 1 and 10"
\n在这种情况下,x
只是为了这些比较而存在(并且实际上基本上没有名字)?还是比较运算符会返回布尔结果和右操作数的计算结果(用于进一步比较)之类的?对于第二个例子的分析扩展使我相信它使用了类似无名中间结果的东西(如果有术语,请教育我),因为它在执行比较之前并不会计算所有的操作数。
在这段代码中,<=
和<
是如何使用的?这个问题的原因是因为在Python中,这两个操作符可以用于比较多个操作数。解决方法是使用dis
模块来查看Python生成的字节码。
通过dis
模块可以让Python告诉你生成的字节码是什么样的。在这段代码中,函数f()
使用了<
和<=
操作符进行比较。下面是使用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
被加载到堆栈上。
因此,在调用input
之前,堆栈如下所示:
input_result 1
DUP_TOP
指令在旋转堆栈顶部的三个值之前,复制了堆栈顶部的值,得到:
1 input_result input_result
COMPARE_OP
指令使用<
操作符测试堆栈上的前两个项,并用结果替换这两个项。
如果结果为False
,则JUMP_IF_FALSE_OR_POP
指令会跳转到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_*
的值。
堆栈中保存了未命名的中间结果以进行比较。这个例子展示了如何使用dis
模块来检查Python生成的字节码,以及<=
和<
操作符在多个操作数中的使用方式。