运算符

  • 举个简单的例子 4 + 5 = 9 。 例子中,4 和 5 被称为操作数,+ 称为运算符。
  • Python 中的运算符用于执行各种操作,例如:执行算术运算、比较值、逻辑操作等。

算术运算符

以下假设变量: a, b = 10, 3

运算符 描述 实例
+ 加法:用于将两个值相加。 a + b = 13
- 减法:用于从一个值中减去另一个值。 a - b = 7
* 乘法:用于将两个值相乘。 a * b = 30
/ 真除法:结果永远是浮点数,即使能整除(4 / 2 得 2.0)。 a / b = 3.3333333333333335
// 地板除(取整除):返回商的向下取整值,操作数也可以是浮点数(10.0 // 3 得 3.0)。注意是向下而不是截断:-7 // 2 得 -4。 a // b = 3
% 取模:返回除法的余数,结果符号跟除数一致:-7 % 2 得 1,7 % -2 得 -1。 a % b = 1
** 幂运算:计算一个值的幂次方,** 是右结合的(2 ** 3 ** 2 等于 2 ** 9)。 a ** b = 1000

补充:divmod(a, b) 一次拿到商和余数(divmod(10, 3) 得 (3, 1));pow(a, b, mod) 是带模幂运算,pow(2, 10, 1000) 得 24。

比较运算符

以下假设变量: a, b = 10, 3

运算符 描述 实例
== 等于:用于检查两个值是否相等。 a == b 返回 False
!= 不等于:用于检查两个值是否不相等。 a != b 返回 True。
> 大于:用于检查一个值是否大于另一个值。 a > b 返回 True。
< 小于:用于检查一个值是否小于另一个值。 a < b 返回 False。
>= 大于等于:用于检查一个值是否大于或等于另一个值。 a >= b 返回 True。
<= 小于等于:用于检查一个值是否小于或等于另一个值。 a <= b 返回 False。

补充:

  • Python 支持链式比较:1 < 2 < 3 等价于 1 < 2 and 2 < 3,但中间那个只求值一次,所以 0 <= f() < 1 只会调用一次 f()。
  • 字符串、元组、列表按逐元素字典序比较:'abc' < 'abd' 为 True,[1, 2, 10] < [1, 3] 为 True(比的是第二个元素,不是长度)。
  • 类型不兼容的比较会抛 TypeError:'2' > 1、None < 1 都不行;Python 2 里能比是历史遗留。
  • == 比的是值,is 比的是身份(见「身份运算符」一节)。

逻辑运算符

以下假设变量: a, b = 10, 3

运算符 逻辑表达式 描述 实例
and x and y 与:两个操作数都按真值判断,返回决定结果的那个操作数本身,不一定是布尔值。 a and b 返回 3。
or x or y 或:同上,返回第一个为真的操作数,都为假时返回最后一个。 a or b 返回 10。
not not x 非:对条件的真值取反,是三个里唯一返回布尔值的。 not a 返回 False

补充:

  • and / or 是短路的:and 左边为假就不再算右边,or 左边为真就不再算右边,所以 x = x or default 能当默认值写法,if d.get('k') and d['k'] > 0: 不会因为键不存在而报错。
  • 正因为返回的是操作数本身,a and b 在 a, b = 10, 3 时得 3 而不是 True;要布尔结果就套一层 bool()。
  • not 的优先级低于比较运算符:not a == b 等于 not (a == b)。
  • 真值判断规则:0、0.0、空字符串、空列表/元组/字典/集合、None 为假,其余为真。

示例:

1
2
3
# 判断是否是闰年
y = int(input('请输入一个年份:'))
print(((y % 4 == 0) and (y % 100 != 0)) or (y % 400 == 0))

赋值运算符

运算符 描述 实例
= 简单赋值:用于将一个值赋给一个变量。 x = 5 赋值
+= 加法赋值:变量加上右侧的值,结果赋回变量。 x += 3 相当于 x = x + 3
-= 减法赋值:变量减去右侧的值,结果赋回变量。 x -= 2 相当于 x = x - 2
*= 乘法赋值:变量乘以右侧的值,结果赋回变量。 x *= 4 相当于 x = x * 4
/= 除法赋值:用变量除以右侧的值,结果赋回变量。 x /= 2 相当于 x = x / 2
%= 取模赋值:用于将左侧的变量取模右侧的值,并将结果赋给该变量。 x %= 3 相当于 x = x % 3
**= 幂赋值:用于将左侧的变量的值提升到右侧的幂,并将结果赋给该变量。 x **= 2 相当于 x = x ** 2
//= 取整除:用于将左侧的变量进行地板除右侧的值,并将结果赋给该变量。 x //= 5 相当于 x = x // 5
&= 按位与赋值 x &= y 相当于 x = x & y
|= 按位或赋值 x |= y 相当于 x = x | y
^= 按位异或赋值 x ^= y 相当于 x = x ^ y
>>= 右移赋值 x >>= 1 相当于 x = x >> 1
<<= 左移赋值 x <<= 1 相当于 x = x << 1

补充:

  • 链式赋值 x = y = 0 让两个名字指向同一个对象,赋可变对象(能原地改内容的对象,如列表、字典、集合;数字、字符串、元组属于不可变对象)时要小心:x = y = [] 之后 x.append(1) 会让 y 也跟着变。
  • 序列解包:a, b = b, a 一行交换;first, *rest = [1, 2, 3] 里 rest 得到 [2, 3]。
  • 赋值运算符里的 &=、\|=、^=、<<=、>>= 说的「按位」,是把整数写成二进制后逐位做运算,规则见下面「位运算符」一节。
  • 增强赋值对可变对象是原地修改(原地 = 不生成新对象,直接把原来那个改掉):lt += [4] 等价于 lt.extend([4]),对象身份不变(指向它的其他引用也看得到);而 lt = lt + [4] 会生成新对象。
  • 海象运算符 :=(Python 3.8+)在表达式里顺便赋值:if (n := len(data)) > 10:。

成员运算符

成员运算符用于检查一个值是否属于某个集合或序列。

运算符 描述
in 如果左侧的值存在于右侧的集合或序列中,则返回 True。
not in 如果左侧的值不存在于右侧的集合或序列中,则返回 True。

补充:

  • 右侧不限于序列:字符串按子串判断('ap' in 'apple' 为 True),字典、集合按键 / 元素判断('a' in d 只看键,不看值)。
  • 自定义类里由 __contains__ 决定;没实现就退回 __iter__,再退回旧的 __getitem__。
  • 性能:列表的 in 是 O(n) 逐个比较,集合和字典是哈希查找平均 O(1),频繁判断存在性就别用列表。

示例:

1
2
3
4
5
6
7
8
9
10
11
fruits = ['apple', 'banana', 'orange']

print('apple' in fruits) # 输出 True,因为 'apple' 存在于 fruits 列表中
print('grape' in fruits) # 输出 False,因为 'grape' 不存在于 fruits 列表中

print('apple' not in fruits) # 输出 False,因为 'apple' 存在于 fruits 列表中
print('grape' not in fruits) # 输出 True,因为 'grape' 不存在于 fruits 列表中

# 若是字典判断的是键
d = {'a': 'apple', 'b': 'banana', 'c': 'cat', 'd': 'dog'}
print('a' not in d) # 输出 False

身份运算符

用于检查两个名字是否指向同一个对象(在 CPython 里就是同一个内存地址)。

运算符 描述
is 两个名字指向同一个对象时返回 True。
is not 两个名字指向不同对象时返回 True。

示例:

1
2
3
4
5
6
7
8
9
10
x = 5
y = 5
z = [1, 2, 3]
w = [1, 2, 3]

print(x is y) # True —— 但原因是 -5~256 的小整数被缓存复用,不是「值相同就同地址」
print(z is w) # False —— 值相同也是两个不同的列表对象

print(x is not y) # False
print(z is not w) # True

补充:

1
2
3
4
5
6
7
8
9
# 值相同不代表同一个对象,别拿 is 当 == 用
a = 1000
b = 1000
print(a == b) # True,值相等
print(a is b) # 不可靠:同一处代码可能被常量折叠成同一个对象,分开求值就是 False

# is 只用来和单例比较:None、True、False,或自己造的哨兵对象
v = None
print(v is None) # True,官方推荐写法(比 == None 快,也不会被自定义 __eq__ 干扰)
  • x is y 成立必然有 x == y(同一个对象当然值相等),反过来不成立。
  • 小整数(-5~256)和形状像标识符的字符串会被缓存复用,所以 is 有时「看起来对」,那是实现细节,不能作为逻辑依据。

位运算符

位运算符用于对二进制数进行操作。

运算符 名称 描述 示例 结果(二进制解释)
& 按位与 两个操作数的对应位都为1时,结果的该位才为1 5 & 3 0101 & 0011 = 0001 (1)
| 按位或 两个操作数的对应位至少有一个为1时,结果的该位为1 5 | 3 0101 | 0011 = 0111 (7)
^ 按位异或 两个操作数的对应位不同时,结果的该位为1 5 ^ 3 0101 ^ 0011 = 0110 (6)
~ 按位取反 对操作数的每一位取反(包括符号位,结果取决于补码表示) ~5 ~00000101 = 11111010 (-6)
<< 左移 将操作数的二进制位向左移动指定位数,低位补0 5 << 1 0101 << 1 = 1010 (10)
>> 右移 将操作数的二进制位向右移动指定位数,高位补符号位(正数补0,负数补1) 5 >> 1 0101 >> 1 = 0010 (2)

补充说明:

  1. ~(按位取反) 的计算方式:
    • Python 使用补码表示负数,~x = -x - 1
    • 例如:~5 = -6,~-3 = 2
  2. 移位运算的特殊情况:
    • 左移 n 位相当于乘以2n(如 5 << 2 = 20,即 5×4)
    • 右移 n 位相当于整除2n(如 5 >> 1 = 2,即 5//2)
  3. 适用数据类型:
    • 仅适用于 整数(int,含 bool),浮点数和复数都会抛 TypeError。另外 Python 的整数是无限精度的,~ 不受固定位宽限制:bin(-5) 显示 -0b101 而不是补码串,想看 8 位补码得自己格式化——format(-5 & 0xFF, '08b') 得 11111011。

示例:

1
2
3
4
5
6
7
8
9
x = 5  # 二进制表示为 0101
y = 3 # 二进制表示为 0011

print(x & y) # 输出 1,二进制表示为 0001
print(x | y) # 输出 7,二进制表示为 0111
print(x ^ y) # 输出 6,二进制表示为 0110
print(~x) # 输出 -6,二进制表示为 1111 1111 1111 1010(补码表示)
print(x << 1) # 输出 10,二进制表示为 1010
print(x >> 1) # 输出 2,二进制表示为 0010
1
2
3
4
5
6
7
8
9
10
11
12
13
14
m = 0b10101   # 十进制 21
n = 0b01011 # 十进制 11
print(m & n) # 1 (0b00001)
print(m | n) # 31 (0b11111)
print(m ^ n) # 30 (0b11110)

k = 0b01
print(~k) # -2
print(k << 1) # 2

# ~k 为什么是 -2:把结果当成补码读回来
# 1 的补码: 0000 0001
# 按位取反: 1111 1110 (这就是 -2 的补码)
# 读成原码: 符号位为 1,数值位取反加一 -> 1000 0010 = -2

运算符优先级

Python 3 的运算符优先级,从高到低(官方表见 表达式参考):

优先级 运算符 说明
最高 () [] {} . 索引与切片、调用、属性访问、容器字面量
↓ await x 等待协程
— x ** y 幂,右结合:2 ** 3 ** 2 是 2 ** 9 = 512
— +x -x ~x 一元正号、负号、按位取反
— * @ / // % 乘、矩阵乘、除、地板除、取模
— + - 加、减
— << >> 移位
— & 按位与
— ^ 按位异或
— | 按位或
— in not in is is not < <= > >= != == 比较、成员、身份运算符全部同级,支持链式 1 < 2 < 3
— not x 逻辑非,优先级低于比较:not a == b 等于 not (a == b)
— and 短路
— or 短路
— x if c else y 条件表达式(三元)
— lambda 匿名函数
— yield x / yield from x 生成器产出
最低 x, y 元组构造(逗号是优先级最低的运算符)

容易记错的几点:

  • 赋值 = 和 += 那一族不在这张表里,它们是语句不是表达式;表达式里唯一带赋值的是海象运算符 :=(3.8+),优先级极低,写的时候几乎总要加括号。
  • 只有 ** 和赋值类是右结合,其余二元运算符都是左结合:8 / 4 / 2 是 (8 / 4) / 2 = 1.0。
  • -2 ** 2 得 -4(先算幂再取负),要 4 就写 (-2) ** 2。
  • 位运算的优先级高于比较:4 & 2 == 0 是 (4 & 2) == 0 得 True(若按 4 & (2 == 0) 算是 0)。所以 x & 1 == 0 判奇偶是对的,但为了可读性建议还是写成 (x & 1) == 0。
  • 比较同级意味着 a == b < c 是合法的链式比较,等价于 a == b and b < c。
  • 这张表是用来看懂代码的,自己写的时候拿不准就加括号。
本文结束 感谢您的阅读
正在加载今日诗词....