## Python语言中的运算符 Python 语言支持很多种运算符,下面的表格按照运算符的优先级从高到低,对 Python 中的运算符进行了罗列。有了变量和运算符,我们就可以构造各种各样的表达式来解决实际问题。在计算机科学中,**表达式是计算机程序中的句法实体,它由一个或多个常量、变量、函数和运算符组合而成,编程语言可以对其进行解释和计算以得到另一个值**。不理解这句话没有关系,但是一定要知道,不管使用什么样的编程语言,构造表达式都是非常重要的。 | 运算符 | 描述 | | ------------------------------------------------------------ | ------------------------------ | | `[]`、`[:]` | 索引、切片 | | `**` | 幂 | | `~`、`+`、`-` | 按位取反、正号、负号 | | `*`、`/`、`%`、`//` | 乘、除、模、整除 | | `+`、`-` | 加、减 | | `>>`、`<<` | 右移、左移 | | `&` | 按位与 | | `^`、`|` | 按位异或、按位或 | | `<=`、`<`、`>`、`>=` | 小于等于、小于、大于、大于等于 | | `==`、`!=` | 等于、不等于 | | `is`、`is not` | 身份运算符 | | `in`、`not in` | 成员运算符 | | `not`、`or`、`and` | 逻辑运算符 | | `=`、`+=`、`-=`、`*=`、`/=`、`%=`、`//=`、`**=`、`&=`、`\|=`、`^=`、`>>=`、`<<=` | 赋值运算符 | >**说明**: 所谓优先级就是在一个运算的表达式中,如果出现了多个运算符,应该先执行什么再执行什么的顺序。编写代码的时候,如果搞不清楚一个表达式中运算符的优先级,可以使用圆括号(小括号)来确保运算的执行顺序。 ### 算术运算符 Python 中的算术运算符非常丰富,除了大家最为熟悉的加、减、乘、除之外,还有整除运算符、求模(求余数)运算符和求幂运算符。下面的例子为大家展示了算术运算符的使用。 ```python """ 算术运算符 Version: 1.0 Author: 骆昊 """ print(321 + 12) # 加法运算,输出333 print(321 - 12) # 减法运算,输出309 print(321 * 12) # 乘法运算,输出3852 print(321 / 12) # 除法运算,输出26.75 print(321 // 12) # 整除运算,输出26 print(321 % 12) # 求模运算,输出9 print(321 ** 12) # 求幂运算,输出1196906950228928915420617322241 ``` 算术运算需要先乘除后加减,这一点跟数学课本中讲的知识没有区别,也就是说乘除法的运算优先级是高于加减法的。如果还有求幂运算,求幂运算的优先级是高于乘除法的。如果想改变算术运算的执行顺序,可以使用英文输入法状态下的圆括号(小括号),写在圆括号中的表达式会被优先执行,如下面的例子所示。 ```python """ 算术运算的优先级 Version: 1.0 Author: 骆昊 """ print(2 + 3 * 5) # 17 print((2 + 3) * 5) # 25 print((2 + 3) * 5 ** 2) # 125 print(((2 + 3) * 5) ** 2) # 625 ``` ### 赋值运算符 赋值运算符应该是最为常见的运算符,它的作用是将右边的值赋给左边的变量。赋值运算符还可以跟上面的算术运算符放在一起,组合成复合赋值运算符,例如:`a += b`相当于`a = a + b`,`a *= a + 2`相当于`a = a * (a + 2)`。下面的例子演示了赋值运算符和复合赋值运算符的使用。 ```python """ 赋值运算符和复合赋值运算符 Version: 1.0 Author: 骆昊 """ a = 10 b = 3 a += b # 相当于:a = a + b a *= a + 2 # 相当于:a = a * (a + 2) print(a) # 大家算一下这里会输出什么 ``` 赋值运算构成的表达式本身不产生任何值,也就是说,如果你把一个赋值表达式放到`print`函数中试图输出表达式的值,将会产生语法错误。为了解决这个问题,Python 3.8 中引入了一个新的赋值运算符`:=`,我们称之为海象运算符,大家可以猜一猜它为什么叫这个名字。海象运算符也是将运算符右侧的值赋值给左边的变量,与赋值运算符不同的是,运算符右侧的值也是整个表达式的值,看看下面的代码大家就明白了。 ```python """ 海象运算符 Version: 1.0 Author: 骆昊 """ # SyntaxError: invalid syntax # print((a = 10)) # 海象运算符 print((a := 10)) # 10 print(a) # 10 ``` > **提示**:上面第 8 行代码如果不注释掉,运行代码会看到`SyntaxError: invalid syntax`错误信息,注意,这行代码中我们给`a = 10`加上了圆括号,如果不小心写成了`print(a = 10)`,会看到`TypeError: 'a' is an invalid keyword argument for print()`错误信息,后面讲到函数的时候,大家就会明白这个错误提示是什么意思了。 ### 比较运算符和逻辑运算符 比较运算符也称为关系运算符,包括`==`、`!=`、`<`、`>`、`<=`、`>=`,我相信大家一看就能懂。需要提醒的是比较相等用的是`==`,请注意这里是两个等号,因为`=`是赋值运算符,我们在上面刚刚讲到过。比较不相等用的是`!=`,跟数学课本中使用的$\small{\neq}$并不相同,Python 2 中曾经使用过`<>`来表示不等于,在 Python 3 中使用`<>`会引发`SyntaxError`(语法错误)。比较运算符会产生布尔值,要么是`True`,要么是`False`。 逻辑运算符有三个,分别是`and`、`or`和`not`。`and`字面意思是“而且”,所以`and`运算符会连接两个布尔值或者产生布尔值的表达式,如果两边的布尔值都是`True`,那么运算的结果就是`True`;左右两边的布尔值有一个是`False`,最终的运算结果就是`False`。当然,如果`and`运算符左边的布尔值是`False`,不管右边的布尔值是什么,最终的结果都是`False`,这时运算符右边的布尔值会被跳过(专业的说法叫短路处理,如果`and`右边是一个表达式,那么这个表达式不会执行)。`or`字面意思是“或者”,所以`or`运算符也会连接两个布尔值或产生布尔值的表达式,如果两边的布尔值有任意一个是`True`,那么最终的结果就是`True`。当然,`or`运算符也是有短路功能的,当它左边的布尔值为`True`的情况下,右边的布尔值会被短路(如果`or`右边是一个表达式,那么这个表达式不会执行)。`not`运算符的后面可以跟一个布尔值,如果`not`后面的布尔值或表达式是`True`,那么运算的结果就是`False`;如果`not`后面的布尔值或表达式是`False`,那么运算的结果就是`True`。 ```python """ 比较运算符和逻辑运算符的使用 Version: 1.0 Author: 骆昊 """ flag0 = 1 == 1 flag1 = 3 > 2 flag2 = 2 < 1 flag3 = flag1 and flag2 flag4 = flag1 or flag2 flag5 = not flag0 print('flag0 =', flag0) # flag0 = True print('flag1 =', flag1) # flag1 = True print('flag2 =', flag2) # flag2 = False print('flag3 =', flag3) # flag3 = False print('flag4 =', flag4) # flag4 = True print('flag5 =', flag5) # flag5 = False print(flag1 and not flag2) # True print(1 > 2 or 2 == 3) # False ``` > **说明**:比较运算符的优先级高于赋值运算符,所以上面的`flag0 = 1 == 1`先做`1 == 1`产生布尔值`True`,再将这个值赋值给变量`flag0`。`print`函数可以输出多个值,多个值之间可以用`,`进行分隔,输出的内容默认以空格分开。 ### 运算符和表达式应用 #### 例子1:华氏温度转摄氏温度 > **要求**:输入华氏温度将其转换为摄氏温度,华氏温度到摄氏温度的转换公式为: $\small{C = (F - 32) / 1.8}$ 。 ```python """ 将华氏温度转换为摄氏温度 Version: 1.0 Author: 骆昊 """ f = float(input('请输入华氏温度: ')) c = (f - 32) / 1.8 print('%.1f华氏度 = %.1f摄氏度' % (f, c)) ``` > **说明**:上面代码中的`input`函数用于从键盘接收用户输入,由于输入的都是字符串,如果想处理成浮点小数来做后续的运算,可以用我们上一课讲解的类型转换的方法,用`float`函数将`str`类型处理成`float`类型。 上面的代码中,我们对`print`函数输出的内容进行了格式化处理,`print`输出的字符串中有两个`%.1f`占位符,这两个占位符会被`%`之后的`(f, c)`中的两个`float`类型的变量值给替换掉,浮点数小数点后保留1位有效数字。如果字符串中有`%d`占位符,那么我们会用`int`类型的值替换掉它,如果字符串中有`%s`占位符,那么它会被`str`类型的值替换掉。 除了上面格式化输出的方式外,Python 中还可以用下面的办法来格式化输出,我们给出一个带占位符的字符串,字符串前面的`f`表示这个字符串是需要格式化处理的,其中的`{f:.1f}`和`{c:.1f}`可以先看成是`{f}`和`{c}`,表示输出时会用变量`f`和变量`c`的值替换掉这两个占位符,后面的`:.1f`表示这是一个浮点数,小数点后保留1位有效数字。 ```python """ 将华氏温度转换为摄氏温度 Version: 1.1 Author: 骆昊 """ f = float(input('请输入华氏温度: ')) c = (f - 32) / 1.8 print(f'{f:.1f}华氏度 = {c:.1f}摄氏度') ``` #### 例子2:计算圆的周长和面积 > **要求**:输入一个圆的半径($\small{r}$),计算出它的周长( $\small{2 \pi r}$ )和面积( $\small{\pi r^{2}}$ )。 ```python """ 输入半径计算圆的周长和面积 Version: 1.0 Author: 骆昊 """ radius = float(input('请输入圆的半径: ')) perimeter = 2 * 3.1416 * radius area = 3.1416 * radius * radius print('周长: %.2f' % perimeter) print('面积: %.2f' % area) ``` Python 中有一个名为`math` 的内置模块,该模块中定义了名为`pi`的变量,它的值就是圆周率。如果要使用 Python 内置的这个`pi`,我们可以对上面的代码稍作修改。 ```python """ 输入半径计算圆的周长和面积 Version: 1.1 Author: 骆昊 """ import math radius = float(input('请输入圆的半径: ')) perimeter = 2 * math.pi * radius area = math.pi * radius ** 2 print(f'周长: {perimeter:.2f}') print(f'面积: {area:.2f}') ``` > **说明**:上面代码中的`import math`表示导入`math`模块,导入该模块以后,才能用`math.pi`得到圆周率的值。 这里其实还有一种格式化输出的方式,是 Python 3.8 中增加的新特性,大家直接看下面的代码就明白了。 ```python """ 输入半径计算圆的周长和面积 Version: 1.2 Author: 骆昊 """ import math radius = float(input('请输入圆的半径: ')) # 输入: 5.5 perimeter = 2 * math.pi * radius area = math.pi * radius ** 2 print(f'{perimeter = :.2f}') # 输出:perimeter = 34.56 print(f'{area = :.2f}') # 输出:area = 95.03 ``` > **说明**:假如变量`a`的值是`9.87`,那么字符串`f'{a = }'`的值是`a = 9.87`;而字符串`f'{a = :.1f}'`的值是`a = 9.9`。这种格式化输出的方式会同时输出变量名和变量值。 #### 例子3:判断闰年 要求:输入一个 1582 年以后的年份,判断该年份是不是闰年。 ```python """ 输入年份,闰年输出True,平年输出False Version: 1.0 Author: 骆昊 """ year = int(input('请输入年份: ')) is_leap = year % 4 == 0 and year % 100 != 0 or year % 400 == 0 print(f'{is_leap = }') ``` > **说明**:对于格里历(Gregorian calendar),即今天我们使用的公历,判断闰年的规则是:1. 公元年份非 4 的倍数是平年;2. 公元年份为 4 的倍数但非 100 的倍数是闰年;3. 公元年份为 400 的倍数是闰年。格里历是由教皇格里高利十三世在 1582 年 10 月引入的,作为对儒略历(Julian calendar)的修改和替代,我们在输入年份时要注意这一点。上面的代码通过`%`来判断`year`是不是`4`的倍数、`100`的倍数、`400`的倍数,然后用`and`和`or`运算符将三个条件组装在一起,前两个条件要同时满足,第三个条件跟前两个条件的组合只需满足其中之一。 ### 总结 通过上面的讲解和例子,相信大家已经感受到了运算符和表达式的力量。实际编程中的很多问题,都需通过构造表达式来解决,所以变量、运算符、表达式对于任何一门编程语言都是极为重要的基础。如果本节课的内容有什么不理解的地方,一定不要着急进入下一课,先在评论区留言讨论,我会及时解答大家的问题。