相关阅读

Pythonhttps://blog.csdn.net/weixin_45791458/category_12403403.html?spm=1001.2014.3001.5482


在C语言和Python中,比较运算符是一个常用的运算符,但这两种语言在某些情况下对比较运算符的解析缺存在差异,本文旨在明确这一点。

Python中的比较运算符串联

首先来看Python官方文档中对比较运算符的定义,下面是定义的BNF范式。

comparison::=or_expr (comp_operator or_expr)*comp_operator ::="" | "==" | ">=" | "<=" | "!=" | "is" ["not"] | ["not"] "in"

BNF显示比较运算的构成是至少一个or_expr表达式和若干个comp_operator运算符、or_expr的组合,本文我们可以简单地把or_expr表达式当做一个常数。其中comp_operator可以是下面三类中的符号。

  • 值比较:小于()、等于(==)、大于等于(>=)、小于等于(<=)、不等于(!=)
  • 标识号比较:是(is)、不是(is not)
  • 成员检测:在…内(in)、不在…内(not in)。

本文只讨论值比较(因为C没有标识号和成员检测比较符),但结论适用于所有比较符。在编程中,我们常常会需要比较三者之间的关系,例如A==B==C,又或者A>B>C…,在Python中,这很好实现,因为Python将多个串联的比较运算符看作是两两组合,并且通过“布尔与”运算符连接。

比如,在Python中,表达式A>B>C几乎等价于A>B and B>C,唯一的差别在于:后一种写法中,子表达式B会被求值两次,而在第一种写法中,子表达式B只会被求值一次(注意:在两种写法中,当A>B为真时,C表达式不会再被求值,这被称作逻辑短路)。

上面的描述也许不够直观,下面来看几个例子加深理解。

例1print(5>4>3)Ture

根据上面的解析规则,例1所示的表达式被近似解析为图1所示的语法分析树。

图1 语法分析树

例2展示了,表达式A>B>C和表达式A>B and B>C之间的细微差别,为了体现求值顺序,我们定义了三个函数,函数内会打印信息,并将其作为比较表达式的子表达式。

例2def func5():print("This is 5")return 5def func4():print("This is 4")return 4def func3():print("This is 3")return 3print(func5() > func4() > func3())This is 5This is 4This is 3Trueprint(func5() > func4() and func4() > func3())This is 5This is 4This is 4 #func4()被求值两次This is 3True

该例不仅展示了func4()函数在两种表达式中的求值次数不同,还侧面验证了之前的文章中说的:Python的求值顺序是从左到右的C&Python:表达式的求值顺序(evaluation order)。

下面的例3展示了比较运算符的逻辑短路性质,需要注意的是:这实际上是由“布尔与”运算符带来的性质。

例3def func5():print("This is 5")return 5def func4():print("This is 4")return 4def func3():print("This is 3")return 3print(func5() < func4() < func3())This is 5This is 4#func3()不求值Falseprint(func5() < func4() and func4() < func3())This is 5This is 4#func3()不求值False

C语言中的比较运算符串联

在使用C语言中的比较运算符时需要更加谨慎,图2是C11中比较运算符的语法。

图2 C11中比较运算符的语法

可以从图2中总结出比较运算表达式从左向右的结合性,即一个比较表达式可以作为一个子表达式称为另一个比较表达式的左操作数,而不是右操作数。举例来说,表达式A>B>C在C语言中会被解析为子表达式A先与子表达式B比较,比较结果再与子表达式C比较,而这不是一般情况下我们想要的比较方式,即A大于B大于C。

下面我们来看一个例子,具体说明上面的描述。

例4#include int main(){printf("The result of expression is %d",5>4>3);}The result of expression is 0

根据上面的解析规则,例4所示的表达式被近似解析为图3所示的语法分析树。

图3语法分析树

那么该如何实现A大于B大于C这种比较呢?其实只用像Python一样,直接显式使用“逻辑与”运算符连接多个比较表达式就可以了,如例4所示。

​例4#include int main(){printf("The result of expression is %d",5>4 && 4>3);}The result of expression is 1

最后顺带一提,C语言也和Python一样拥有逻辑短路性质,即使之前的文章说过,C语言不保证很多表达式的求值顺序,但对于几个特殊的表达式规定了求值顺序,其中就包含“逻辑与”运算符:首先求值&&的左操作数,再求值&&的右操作数,并且拥有逻辑短路性质,下面举例说明。

例5#include int func5(){printf("This is 5\n");return 5;}int func4(){printf("This is 4\n");return 4;}int func3(){printf("This is 3\n");return 3;}int main(){printf("The result of expression is %d",func5()func3());}This is 5This is 4//func3没有被求值The result of expression is 0