前言
本文将介绍Python语言中一些主要的运算符(也称操作符),包括算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符和其他运算符。
一、算术运算符
Python中的算术运算符用来组织整型和浮点型数据的算术运算,按照参加运算的操作数的不同可分为一元运算符和二元运算符。
1.1 一元运算符
Python中一元运算符有多个,但是算术一元运算符只有一个,即 -,- 是取反运算符,例如:-a 是对 a 取反运算。
在 Python Shell 中运行示例代码如下:
>>> a = 12
>>> -a
-12
>>>
上述代码是将变量 a 取反,结果输出为 -12。
1.2 二元运算符
+、-、*、/、%、** 和 //。这些运算符主要是对数字类型数据进行操作,而 + 和 * 还可以用于字符串、元组和列表等类型的数据操作,具体说明请参见表 1-1。
表1-1 二元算术运算符
运算符 | 名称 | 说明 | 例子 |
+ | 加 | 可用于数字、序列等类型数据操作 对于数字类型是求和;其他类型是连接操作 | a + b |
- | 减 | 求 a 减 b 的差 | a - b |
* | 乘 | 可用于数字、序列等类型数据操作 对于数字类型是乘积;其他类型是重复操作 | a * b |
/ | 除 | 求 a 除以 b 的商 | a / b |
% | 取余 | 求 a 除以 b 的余数 | a % b |
** | 幂 | 求 a 的 b 次幂 | a ** b |
// | 地板除法 | 求不大于 a 除以 b 的商的最大整数(向下取整) | a // b |
在 Python Shell 中运行示例代码如下:
>>> 1 + 2
3
>>> 2 - 1
1
>>> 2 * 3
6
>>> 3 / 2
1.5
>>> 3 % 2
1
>>> 3 // 2
1
>>> 4 // 2
2
>>> -3 // 2
-2
>>> 10 ** 2
100
>>> 10.0 + True + 2
13.0
>>> 10.0 + False + 2
12.0
>>>
《说明》布尔值:True 和 False 在参与算术运算时,True 的值为1,False 的值为0。
字符串属于序列的一种,所以字符串可以使用 “+” 和 “*” 运算符,在Python Shell 中运行示例代码如下:
>>> 'Hello' + 'World'
'HelloWorld'
>>> 'Hello' + 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "int") to str
>>> 'Hello' * 2
'HelloHello'
>>> 'Hello' * 2.2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't multiply sequence by non-int of type 'float'
>>> 'Hello' * 0
''
>>> 'Hello' * -1
''
>>> 'Hello' * -2
''
>>>
“+” 运算符会将两个字符串连接起来,但不能将字符串与其他类型数据连接起来,否则会报错。
“*” 运算符第一操作数是字符串,第二操作数是整数,表示重复字符串的次数。因此 'Hello' * 2 结果为:'HelloHello'。注意,第二操作数只能是整数,如果是 0 或 负整数,则会得到空字符串结果。
二、关系运算符
==、!=、>、<、>= 和 <=,具体说明请参见表2-2。
表2-2 关系运算符
运算符 | 名称 | 例子 | 说明 |
== | 等于 | a == b | a 等于 b 时返回True,否则返回 False |
!= | 不等于 | a != b | 与 == 相反 |
> | 大于 | a > b | a 大于 b 时返回 True,否则返回 False |
< | 小于 | a < b | a 小于 b 时返回 True,否则返回 False |
>= | 大于或等于 | a >= b | a 大于或等于 b 时返回 True,否则返回 False |
<= | 小于或等于 | a <= b | a 小于或等于 b 时返回 True,否则返回 False |
在 Python Shell 中运行示例代码如下:
>>> a = 1
>>> b = 2
>>> a > b
False
>>> a < b
True
>>> a >= b
False
>>> a <= b
True
>>> 1.0 == 1
True
>>> 1.0 != 1
False
Python 中关系运算符可用于比较序列或数字类型,整数、浮点数都是对象,可以使用关系运算符进行比较;字符串、列表和元组属于序列,也可以使用关系运算符进行比较。
在Python Shell 中运行示例代码如下:
>>> a = 'Hello'
>>> b = 'Hello'
>>> a == b
True
>>> a = 'World'
>>> a > b
True
>>> a < b
False
>>>
>>> a = [] # --1
>>> b = [1, 2] # --2
>>> a == b
False
>>> a < b
True
>>> a = [1, 2]
>>> a == b
True
代码第1处创建一个空列表,代码第2处创建一个有两个元素的列表,它们也可以进行大小比较。
三、逻辑运输符
逻辑运输符是对布尔型变量进行运算,其结果也是布尔型。具体说明参见表3-3。
表3-3 逻辑运输符
运算符 | 名称 | 例子 | 说明 |
not | 逻辑非 | not a | a 为True时,计算结果为False;a 为 False时,计算结果为 True |
and | 逻辑与 | a and b | a, b 全为True时,计算结果为True;否则为 False |
or | 逻辑或 | a or b | a, b全为 False时,计算结果为 False;否则为 True |
Python中的 “逻辑与” 和 “逻辑或” 都采用 “短路” 设计。例如,a and b,如果 a 为 False,则不计算 b(因为不论 b 为何值,“逻辑与” 操作结果都为 False);而对于 a or b,如果 a 为 True,则不计算 b(因为不论 b 为何值,“逻辑或” 操作的结果都为 True)。
这种短路形式的设计,使它们在计算过程中就像电路短路一样采用最优化的计算方式,从而提高效率。
示例代码如下:logic_operator.py
# coding=utf-8
# 代码文件: 运算符/logic_operator.py
# 逻辑运算符的使用
i = 0
a = 10
b = 9
if a > b or i ==1:
print("逻辑或运算为 真")
else:
print("逻辑或运算为 假")
if a < b and i == 1:
print("逻辑与运算为 真")
else:
print("逻辑与运算为 假")
def func1(): # --1
print("--func1--")
return a > b
def func2(): # --2
print("--func2--")
return a == b
print( func1() or func2()) # --3
程序运行结果:
F:\python_work\Python基础\运算符>python logic_operator.py
逻辑或运算为 真
逻辑与运算为 假
--func1--
True
上述代码第1处和第2处定义的两个函数返回的是布尔值。代码第3处进行 “逻辑或” 运算,由于短路计算方式,func1() 函数返回 True 之后,不再调用 func2() 函数。
四、位运算符
&、|、^、~、>> 和 <<。具体说明请参见表4-4。
表4-4 位运算符
运算符 | 名称 | 例子 | 说明 |
& | 按位与 | x & y | x 与 y 进行按位与运算 |
| | 按位或 | x | y | x 与 y 进行按位或运算 |
^ | 按位异或 | x ^ y | x 与 y 进行按位异或运算 |
~ | 按位取反 | ~x | 将 x 进行按位取反运算 |
>> | 右移 | x >> a | x 右移 a 位,高位采用符号位补位 |
<< | 左移 | x << a | x 左移 a 位,低位用 0 补位 |
位运算符的运算规则,请参见下表4-5。
表4-5 位运算符的运算规则
第一个操作数 | 第二个操作数 | 按位与 | 按位或 | 按位异或 |
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 0 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
位运算示例代码:bit_operator.py
# coding=utf-8
# 代码文件: 运算符/bit_operator.py
a = 0b10110010 # 178 --1
b = 0b01011110 # 94 --2
print("a | b = {0}".format(a | b)) # 0b11111110(254) --3
print("a & b = {0}".format(a & b)) # 0b00010010(18) --4
print("a ^ b = {0}".format(a ^ b)) # 0b11101100(236) --5
print("~a = {0}".format(~a)) # -179 --6
print("a >> 2 = {0}".format(a >> 2)) # 0b00101100(44) --7
print("a << 2 = {0}".format(a << 2)) # 0b11001000(712) --8
c = -0b1100 # -12 --9
print("c >> 2 = {0}".format(c >> 2)) # -0b00000011(-3) --10
print("c << 2 = {0}".format(c << 2)) # -0b00110000(-48) --11
运行结果:
F:\python_work\Python基础\运算符>python bit_operator.py
a | b = 254
a & b = 18
a ^ b = 236
~a = -179
a >> 2 = 44
a << 2 = 712
c >> 2 = -3
c << 2 = -48
上述代码中,第1处和第2处分别声明了整型变量 a 和 b,采用二进制表示。第9处声明了整型变量 c,也是采用二进制表示,注意其前面使用了负号,表示这是一个负整数(-12)。
《注意》a 和 b 位数是与本机相关的,虽然只写出了8位,但笔者计算机是 64 位(x86_64)的,所以 a 和 b都是64位数字,只是在本例中省略了前面56个零。位数多少并不会影响按位取反和移位运算。
《提示》Windows系统中,在Dos命令提示符中输入:systeminfo 命令,可以查看计算机系统关键信息,其中
系统类型: x64-based PC
即 “基于x64的 计算机”。
(1)上述代码第3处 (a | b) 表达式是进行位或运算,结果是二进制的 0b1111 1110(十进制是 254),它的运算过程如下图4-1所示。从图中可见,a 和 b 按位进行或运算,只要有一个为1,计算结果为1,否则为0。
图4-1 位或运算
(2)代码第4处 (a & b) 表达式是进行位与运算,结果是二进制的 0b0001 0010(十进制是 18),它的运算过程如下图4-2所示。从图中可知,a 和 b 按位进行与运算,只有两位全部为1,这一位才为1,否则为0。
图4-2 位与运算
(3)代码第5处 (a ^ b) 表达式是进行异或运算,结果是二进制的 0b1110 1100(十进制的 236),它的运算过程如下图4-3所示。从图中可知,a 和 b 按位进行异或运算,只有两位的二进制数不同时这一位才为1,否则为0。
图4-3 异或位运算
(4)代码第6处 (~a) 表达式是按位取反运算,这个过程中需要补码运算,而且与计算机位数有关。笔者使用的是 64 位计算机,所以计算结果为 -179,下面截图是计算过程。a = 0b1011 0010(178)
图4-4 变量a的二进制表示
然后,对变量 a 的每一位二进制位进行取反操作,也包括最高位(第64位)符号位,结果如下。
图4-5 ~a运算后的二进制结果
从图4-5可以看到,执行 ~a 运算后,最高位为1,表示这是一个负数,而负数是用补码表示的,也就是说此时内存中保存的这个数是一个负数的补码形式,那么要怎样倒推出这个负数的原码形式呢?
负数原码 —> 补码规则:符号位不变,数值位取反加1。
补码 —> 负数原码:符号位不变,数值位取反加1。
<备注> 正整数原码和补码是相同的,因此正整数没有补码一说;负整数在内存中是以其补码的形式存放的,而不是以原码的形式存放,这一点要特别注意。
~a —> 1,111 ... 0100 1101 (其最高位为1,表示这是一个负整数)
1,111 1111 ... 0100 1101 符号位不变,数值位按位取反得到:1,000 0000 ... 1011 0010
1,000 0000 ... 1011 0010 + 1 —> 1,000 0000 ... 1011 0011 —> -179 (整数179的二进制原码表示为:0b1011 0011,整数-179的二进制原码表示为:-0b1011 0011)
>>> 0b10110011
179
>>> -0b10110011
-179
综上分析可知,~a 运算得到的结果为 -179(其在内存单元中以补码的形式存放)。
(5)代码第7处 (a >> 2) 表达式是进行右移 2 位运算,结果是二进制的 0b0010 1100(十进制是44),它的运算过程如下图4-6所示。从图中可见,a 的低位被移除掉,高位用 0 补位(注意最高位不是1,而是0,在1前面还有56个0)。
图4-6 右移2位运算
(6)代码第8处 (a << 2) 是进行左移 2 位运算,结果是二进制的 0b10 1100 1000(十进制是712),它的运算过程如下图4-7所示。从图中可见,由于本机是64位,所以高位不会移除掉,低位用 0 补位。但是需要注意,如果本地是 8 位的,高位会被移除掉,结果是二进制的 0b1100 1000(十进制是 310)。
图4-7 左移2位运算
提示:代码第10处和第11处是对负数进行移位运算,负数也涉及补码运算。如果对负数移位运算不理解可以先忽略负号当成正整数进行,然后运算出结果后再加上负号。
提示:右移 n 位,相当于操作数除以
,例如代码第7处 (a >> 2) 表达式相当于 (a /
),178 / 4 所以结果等于44。另外,左移 n 位,相当于操作数乘以
,例如代码第8处 (a << 2) 表达式相当于 (a *
),178 * 4 所以结果等于712。
五、赋值运算符
赋值运算符只是一种简写,一般用于变量自身的变化,例如 a 与其操作数进行运算的结果赋值给 a,算术运算符和位运算符中的二元运算符都有对应的赋值运算符。具体说明请参见下表 5-6 所示。
表5-6 算术赋值运算符
运算符 | 名称 | 例子 | 说明 |
+= | 加赋值 | a += b | 等价于 a = a + b |
-= | 减赋值 | a -= b | 等价于 a = a - b |
*= | 乘赋值 | a *= b | 等价于 a = a * b |
/= | 除赋值 | a /= b | 等价于 a = a / b |
%= | 取余赋值 | a %= b | 等价于 a = a % b |
**= | 幂赋值 | a **= b | 等价于 a = a ** b |
//= | 地板除法赋值 | a //= b | 等价于 a = a // b |
&= | 位与赋值 | a &= b | 等价于 a = a & b |
|= | 位或赋值 | a |= b | 等价于 a = a | b |
^= | 位异或赋值 | a ^= b | 等价于 a = a ^ b |
<<= | 左移赋值 | a <<= b | 等价于 a = a << b |
>>= | 右移赋值 | a >>= b | 等价于 a = a >> b |
assignment_operator.py
# coding=utf-8
# 代码文件: 运算符/assignment_operator.py
a = 1
b = 2
a += b # 相当于a=a+b
print("a + b = {0}".format(a)) # a=1,b=2 运算结果为:3
a += b + 3 # 相当于a=a+b+3
print("a + b + 3 = {0}".format(a)) # a=3,b=2 运算结果为:8
a -= b; # 相当于a=a-b
print("a - b = {0}".format(a)) # a=8,b=2 运算结果为:6
a *= b # 相当于a=a*b
print("a * b = {0}".format(a)) # a=6,b=2 运算结果为:12
a /= b # 相当于a=a/b
print("a / b = {0}".format(a)) # a=12,b=2 运算结果为:6.0
a %= b # 相当于a=a%b
print("a % b = {0}".format(a)) # a=6,b=2 运算结果为:0.0
a = 0b10110010
b = 0b01011110
a |= b # 相当于a=a|b
print("a | b ={0}".format(a)) # a=0b10110010,b=0b01011110 运算结果为:0b11111110(254)
a ^= b # 相当于a=a^b
print("a ^ b = {0}".format(a)) # a=0b11111110,b=0b01011110 运算结果为:0b10100000(160)
六、其他运算符
除了前面介绍的主要运算符,Python还有一些其他运算符,如 索引运算符以及两个比较重要的 “测试”运算符,这两个“测试”运输符是同一性测试运输符和成员测试运输符,所谓“测试”就是判断之意,因此它们的运算结果是布尔值,它们也属于关系运算符。
6.1 索引运输符
索引运输符就是使用方括号[ ],在方括号中既可使用单个索引值,也可使用索引范围。实际上,在使用索引范围时,还可指定步长。
下面代码示范了在索引运输符的使用方法以及在索引范围中指定步长的用法。
程序清单:index_operator.py
# coding=utf-8
# 代码文件: 运算符/index_operator.py
# 索引运算符的使用
a = 'abcdefghijklmn'
# 获取索引2到索引8的子串
print(a[2:8]) # 输出:cdefgh
# 获取索引2到索引8的子串,步长为2
print(a[2:8:2]) # 输出:ceg
# 获取索引2到索引8的子串,步长为3
print(a[2:8:3]) # 输出:cf
从输出结果可以得知:
1、索引值是从 0 开始计算的。
2、索引运算符的索引范围[a:b]是一个半闭半开的索引规则,即其索引的范围是 a ~ b-1,并没有包含索引值b,这样做的好处是当我们要计算索引范围的长度时,直接通过计算(b - a)即可获得。
6.2 同一性测试运算符(is 和 is not)
同一性测试运算符就是测试两个对象是否是同一个对象,类似于 == 运算符,不同之处是,== 是测试两个对象的内容是否相同,当然如果是同一对象 == 也返回 True。
同一性测试运算符有两个:is 和 not is,is 是判断是同一对象,is not 是判断不是同一对象。
示例代码如下:is_isNot_operator.py
# coding=utf-8
# 代码文件: 运算符/is_isNot_operator.py
# 同一性测试运算符:is 和 is not
class Person: # --1
def __init__(self, name, age):
self.name = name
self.age = age
p1 = Person("Tony", 18)
p2 = Person("Tony", 18)
print("p1 == p2: {0}".format(p1 == p2)) # False
print("p1 is p2: {0}".format(p1 is p2)) # False
print("p1 != p2: {0}".format(p1 != p2)) # True
print("p1 is not p2: {0}".format(p1 is not p2)) # True
即 p1 is p2 为 True?)程序运行结果却不是,因为这里实例化了两个Person类对象(Person("Tony", 18)
那么 p1 == p2 为什么会返回 False 呢?因为 == 虽然是比较两个对象的内容是否相等,但是也需要告诉对象比较的规则是什么,是比较 name 还是比较 age?这需要在定义类时重写 __eq__()
修改代码如下:is_isNot_operator2.py
# coding=utf-8
# 代码文件: 运算符/is_isNot_operator.py
# 同一性测试运算符:is 和 is not
class Person: # --1
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, other):
if self.name == other.name and self.age == other.age:
return True
else:
return False
p1 = Person("Tony", 18)
p2 = Person("Tony", 18)
print("p1 == p2: {0}".format(p1 == p2)) # True
print("p1 is p2: {0}".format(p1 is p2)) # False
print("p1 != p2: {0}".format(p1 != p2)) # False
print("p1 is not p2: {0}".format(p1 is not p2)) # True
运行结果:
F:\python_work\Python基础\运算符>python is_isNot_operator.py
p1 == p2: True
p1 is p2: False
p1 != p2: False
p1 is not p2: True
上述代码重写了 __eq__() 方法,其中定义了只有在 name 和 age 都同时相等时,两个Person类对象 p1 和 p2 才相等,即 p1 == p2 为 True。注意,p1 is p2 还是为 False 的。有关类和对象等细节问题,我们读者只需要知道 is 和 == 两种运算符的不同即可。
6.3 成员测试运算符(in 和 not in)
成员测试运算符可以测试在一个序列(sequence)对象中是否包含某一个元素。成员测试运算符也有两个:in 和 not in,in 是测试是否包含某一个元素,not in 是测试是否不包含某一个元素。其运算结果同样是布尔值,也属于关系运算符范畴。
示例代码如下:in_notIn_operator.py
# coding=utf-8
# 代码文件: 运算符/in_notIn_operator.py
# 成员测试运算符:in 和 not in
string_a = 'Hello'
print('e' in string_a) # True --1
print('ell' not in string_a) # False --2
list_a = [1, 2]
print(2 in list_a) # True --3
print(1 not in list_a) # False --4
上述代码第1处是判断字符串 "Hello" 中是否包含字符 e;代码第2处是判断字符串 "Hello" 中是否不包含字符串 "ell",这里需要注意的是字符串本质也属于序列,此外还有列表(list) 和 元组 都属于序列。
上述代码第3处是判断 list_a 列表中是否包含元素 2;代码第4处是判断 list_a 列表中是否不包含元素 1。
6.4 三目运算符
Python 没有自带三目运算符(条件 ? 表达式1 : 表达式2),但是可以通过 if 语句来实现三目运算符的功能,因此可以近似地把这种 if 语句当成三目运算符。作为三目运算符的 if 语句的语法格式如下:
True_statements if expression else False_statements
三目运算符的规则是:先对逻辑表达式 expression 求值,如果逻辑表达式返回 True,则执行并返回 True_statements 的值;如果逻辑表达式返回 False,则执行并返回 False_statements 的值。
示例代码如下:
>>> a = 5
>>> b = 3
>>> st = "a 大于 b" if a > b else "a 不大于 b"
>>> print(st)
a 大于 b
实际上,如果只是为了在Python Shell 控制台输出提示信息,还可以将上面的三目运算符表达式改为如下形式:
>>> print("a 大于 b") if a > b else print("a 不大于 b")
a 大于 b
Python 允许在三目运算符的 True_statements 或 False_statements 中放置多条语句。Python 主要支持两种放置方式。
- 多条语句以英文逗号隔开:每条语句都会执行,程序返回多条语句的返回值组成的元组。
- 多条语句以英文分号隔开:每条语句都会执行,程序只返回第一条语句的返回值。
(1)先看第一种情形,使用如下代码:ternary_operator.py
# coding=utf-8
# 代码文件: 运算符/ternary_operator.py
# 三目运算符
a = 5
b = 3
# 第一个返回值部分使用两条语句,用逗号隔开
st = print("crazyit"), 'a 大于 b' if a > b else 'a 不大于 b'
print(st)
运行结果:
F:\python_work\Python基础\运算符>python ternary_operator.py
crazyit
(None, 'a 大于 b')
上面程序中,True_statements 为 print("crazyit"), 'a 大于 b',这两条语句都会执行,从运行结果可以看出,程序返回了这两条语句的返回值组成的元组。由于 print() 函数没有返回值,相当于它的返回值是 None,所以,print(st) 的输出结果为:(None, 'a 大于 b')。
(2)再看第二种情形,如果将上面语句中的逗号改为分号,将逗号之后的语句改为赋值语句,即写成如下形式:
# 第一个返回值部分使用两条语句,用分号隔开
st = print("crazyit"); 'a 大于 b' if a > b else 'a 不大于 b'
print(st)
运行结果:
F:\python_work\Python基础\运算符>python ternary_operator.py
crazyit
None
此时虽然 True_statements 包含两条语句,但程序只会返回第一条语句 print("crazyit") 的返回值,该语句同样返回 None。
需要指出的是,三目运算符支持嵌套,通过嵌套三目运算符,可以执行更复杂的判断。
例如,下面代码需要判断 x、y 两个变量的大小关系。
x = 5
y = 5
# 判断x、y的大小关系
print("x大于y") if x > y else (print("x小于y") if x < y else print("x等于y"))
运行结果:
x等于y
print("x大于y");否则系统将会计算 else 后面的内容:print("x小于y") if x < y else print("x等于y"),这个表达式又是一个嵌套的三目运算符表达式——注意,进入该表达式时只剩下 “x 小于 y” 或 “x 等于 y” 这两种情况,因此三目运算符再次判断 x < y,如果该表达式为 True,将会输出 "x小于y",否则只剩下 "x等于y"
七、运算符的结合性和优先级
所有的算术运算都是从左向右进行的,Python 语言中的大部分运算符也是从左向右结合的,只有单目运算符、赋值运算符(=)和三目运算符例外,它们是从右向左结合的,也就是说,它们是从右向左运算的。
乘法和加法是两个可结合的运算符,也就是说,这两个运算符左右两边的操作数可以互换位置而不会影响结果。
运算符有不同的优先级,所谓优先级就是在表达式运算中的先后运算顺序。
下表 7-7 中列出了包括分隔符在内的所有运算符的优先级顺序。
表7-7 运算符优先级
优先级 | 运算符 | 说明 |
1 | () | 小括号 |
2 | func(参数) | 函数调用 |
3 | [start: end], [start: end: step] | 索引运算符 |
4 | [index] | 下标 |
5 | . | 引用类成员 |
6 | ** | 幂运算 |
7 | ~ | 按位取反 |
8 | +, - | 正负号 |
9 | *, /, % | 乘法、除法、取余 |
10 | +, - | 加法、减法 |
11 | <<, >> | 左移、右移 |
12 | & | 按位与 |
13 | ^ | 按位异或 |
14 | | | 按位或 |
15 | in,not in,is,is not,<,<=,>,>=,!=,== | 关系运算符 |
16 | not | 逻辑非 |
17 | and | 逻辑与 |
18 | or | 逻辑或 |
19 | lambda | Lambda 表达式 |
通过上表7-7,我们对Python运算符优先级可以有一个大体上的了解,知道运算符优先级大体顺序从高到低是:
算术运算符—>位运算符—>关系运算符—>逻辑运算符—>赋值运算符。
例如,我们分析 4+4<<2 语句的执行结果。程序先执行 4+4 得到结果8,再执行 8<<2 得到32。如果使用 "()" 就可以改变程序的执行顺序,比如 4+(4<<2),则先执行 4<<2,得到结果16,再执行4+16,得到结果20。
虽然 Python 运算符存在优先级的关系,但并不推荐过度依赖运算符的优先级,因为这会导致程序的可读性降低。因此,在这里要提醒读者:
- 不要把一个表达式写得过于复杂,如果一个表达式过于复杂,则把它分成多步来完成。
- 不要过多地依赖运算符优先级来控制表达式的执行顺序,这样可读性太差,应尽量使用小括号来控制表达式的执行顺序。
参考
《Python从小白到大牛(第1版-2018).pdf》第7章 - 运算符
《疯狂Python讲义(2018.12).pdf》第2章 - 变量和简单类型