运算符
- 举个简单的例子
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 | # 判断是否是闰年 |
赋值运算符
| 运算符 | 描述 | 实例 |
|---|---|---|
= |
简单赋值:用于将一个值赋给一个变量。 | 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 | fruits = ['apple', 'banana', 'orange'] |
身份运算符
用于检查两个名字是否指向同一个对象(在 CPython 里就是同一个内存地址)。
| 运算符 | 描述 |
|---|---|
is |
两个名字指向同一个对象时返回 True。 |
is not |
两个名字指向不同对象时返回 True。 |
示例:
1 | x = 5 |
补充:
1 | # 值相同不代表同一个对象,别拿 is 当 == 用 |
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) |
补充说明:
~(按位取反) 的计算方式:- Python 使用补码表示负数,
~x = -x - 1 - 例如:
~5 = -6,~-3 = 2
- Python 使用补码表示负数,
- 移位运算的特殊情况:
- 左移
n位相当于乘以2n(如5 << 2 = 20,即 5×4) - 右移
n位相当于整除2n(如5 >> 1 = 2,即 5//2)
- 左移
- 适用数据类型:
- 仅适用于 整数(
int,含bool),浮点数和复数都会抛TypeError。另外 Python 的整数是无限精度的,~不受固定位宽限制:bin(-5)显示-0b101而不是补码串,想看 8 位补码得自己格式化——format(-5 & 0xFF, '08b')得11111011。
- 仅适用于 整数(
示例:
1 | x = 5 # 二进制表示为 0101 |
1 | m = 0b10101 # 十进制 21 |
运算符优先级
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。 - 这张表是用来看懂代码的,自己写的时候拿不准就加括号。