Python 语法篇 · 第3章

运算符与表达式

运算符是数据之间"做运算"的规则。本章系统梳理 Python 的全部常用运算符、短路求值、链式比较与运算符优先级。

🎯 学习目标

  • 掌握算术、赋值、比较、逻辑、成员、身份、位运算符的用法
  • 理解 / 与 //、% 在负数时的行为
  • 彻底搞懂 and/or 的短路求值与返回值规则
  • 会写 Python 风格的链式比较与三元表达式
  • 了解海象运算符 := 与位运算的典型用途
  • 能依据优先级表判断复杂表达式的计算顺序

1算术运算符

运算符含义示例结果
+加法(字符串/列表还可拼接)3 + 25
-减法 / 负号3 - 21
*乘法(字符串可重复)"ab" * 3'ababab'
/真除法(结果必为 float)7 / 23.5
//整除(向下取整)7 // 23
%取余(模运算)7 % 21
**幂运算2 ** 101024
# 整除与取余满足关系:a == (a // b) * b + (a % b)
print(-7 // 2)     # -4   向负无穷方向取整(不是 -3!)
print(-7 % 2)      # 1    由上面的恒等式推出
print(7 // -2)     # -4
print(7 % -2)      # -1

# % 的实用场景
print(10 % 3)          # 1:判断整除、周期性问题
print("成绩:%5d" % 88) # % 还可用于旧式字符串格式化
print(divmod(17, 5))   # (3, 2):一次拿到商和余数

% 常见用途:判断奇偶 n % 2 == 0、判断整除 n % 5 == 0、秒数转"分:秒"f"{s // 60}:{s % 60:02d}"、环形队列取索引。

2赋值运算符

x = 10           # 基本赋值
x += 3           # 等价 x = x + 3        → 13
x -= 1           # x = x - 1            → 12
x *= 2           # 24
x /= 4           # 6.0(/= 后变 float)
x //= 2          # 3.0
x %= 2           # 1.0
x **= 3          # 1.0

# 其他语言里的 x++ / x-- 在 Python 中【不存在】,请写 x += 1

复合赋值对可变对象有特殊行为:lst += [4] 是原地修改列表;而 lst = lst + [4] 是生成新列表。这一差异在函数传参、默认参数场景会引发隐蔽 bug,第 6、7 章会再遇到。

海象运算符 :=(Python 3.8+)

海象运算符(walrus operator)在表达式内部完成"赋值 + 使用",常用于减少重复计算:

# 传统写法:先计算再判断
line = input("输入:")
while line != "quit":
    print("你输入了", line)
    line = input("输入:")

# 海象写法:输入、判断二合一
while (line := input("输入:")) != "quit":
    print("你输入了", line)

# 避免重复调用 len()
text = "hello world"
if (n := len(text)) > 5:
    print(f"文本长度 {n} 超过 5")

3比较运算符

运算符含义示例
==值相等1 == 1.0 → True
!=不相等"a" != "b"
> / <大于 / 小于3 > 2
>= / <=大于等于 / 小于等于5 >= 5

比较运算的结果一定是 bool(True/False)。Python 支持极具可读性的链式比较:

score = 75
print(60 <= score < 90)        # True,数学写法直接用
# 等价于 (60 <= score) and (score < 90),但 score 只求值一次

print(1 < 2 < 3)              # True
print(1 < 2 == 2)             # True

# 字符串按字典序逐字符比较(比 Unicode 码点)
print("apple" < "banana")     # True
print("abc" < "abd")          # True
print("a" < "A")              # False(小写字母码点更大:ord('a')=97 > ord('A')=65)

4逻辑运算符:and / or / not

True and False    # False   与:两者都真才真
True or False     # True    或:任一为真即真
not True          # False   非:取反

age = 25
print(age >= 18 and age <= 60)    # True
print(not (age < 18))             # True

4.1 短路求值(重要)

Python 的 and、or 会从左到右计算,一旦结果确定就立即停止,右侧表达式根本不会执行:

# and:左假即假,右边短路不执行
False and print("不会打印")

# or:左真即真,右边短路不执行
True or print("不会打印")

# 经典保护:先判断非空,再取下标,避免 IndexError
data = []
if data and data[0] > 0:
    print("有正数")

# 除零保护
b = 0
if b != 0 and 10 / b > 1:
    print("安全")

4.2 and/or 返回的不一定是布尔值

这是 Python 与很多语言不同的设计:and/or 返回的是参与运算的某个对象本身,而不是强制变成 True/False:

# x and y:x 为假 → 返回 x;否则返回 y
print(0 and "hello")     # 0
print(3 and "hello")     # hello

# x or y:x 为真 → 返回 x;否则返回 y
print("a" or "b")        # a
print("" or "默认值")    # 默认值

print(not "abc")         # False(not 会强制返回 bool)
print(not "")            # True

利用这一特性可以写简洁的默认值惯用法(但语义不清时不要滥用):

username = input("昵称(留空则为游客):")
name = username or "游客"       # 留空(""为假)时回退到"游客"
print("欢迎," + name)

5成员运算符与身份运算符

# in / not in:判断"是否包含",适用于字符串、列表、元组、字典、集合
print("py" in "python")        # True
print(3 in [1, 2, 3])          # True
print("name" in {"name": "张三"})  # True(字典判断的是键)
print(5 not in (1, 2, 3))      # True

# is / is not:判断是否同一个对象(身份比较)
x = None
print(x is None)               # 判断 None 的标准写法
a = b = [1]
print(a is b)                  # True

# == 比值;is 比身份
print([1, 2] == [1, 2])        # True
print([1, 2] is [1, 2])        # False

规则:值比较一律 ==;只有与单例对象比较时用 is——最常见的就是 is None / is not None。不要写 x is 100 这类代码(小整数缓存是 CPython 实现细节)。

6位运算符(了解为主)

位运算直接操作整数的二进制位,在算法题、权限标志、嵌入式/高性能场景使用:

运算符含义示例(以 5=101₂、3=011₂ 为例)
&按位与5 & 3 → 1(001)
|按位或5 | 3 → 7(111)
^按位异或5 ^ 3 → 6(110,相同为0不同为1)
~按位取反~5 → -6
<<左移(低位补0)1 << 3 → 8(等于 ×8)
>>右移8 >> 2 → 2(等于 //4)
# 实用:不用乘除做 2 的倍数运算(高性能场景)
print(1024 << 1)    # 2048
print(1024 >> 1)    # 512

# 判断奇偶:看最低位
print((n := 7) & 1)    # 1 奇数;0 偶数

# 权限标志:用不同二进制位组合权限
READ, WRITE, EXEC = 1, 2, 4
perm = READ | WRITE        # 授予 读+写 = 3
print(bool(perm & READ))   # True:检查是否有读权限

7三元表达式

Python 的条件表达式读作"真值 if 条件 else 假值",用于一行完成简单的二选一:

score = 58
result = "及格" if score >= 60 else "不及格"
print(result)        # 不及格

# 等价于:
# if score >= 60:
#     result = "及格"
# else:
#     result = "不及格"

print(max(3, 9))                         # 9
# 手写一个 max 也可以用三元表达
bigger = a if (a := 3) > (b := 9) else b
print(bigger)                            # 9

三元表达式只适合简短的二选一;分支逻辑复杂时请老老实实写 if/else,可读性优先。

8运算符优先级

优先级决定"先算谁",下表从高到低列出常用运算符(完整版可查官方文档):

优先级运算符说明
高**幂运算(右结合:2**3**2 == 2**9)
↓~ + -按位取反、正负号
* / // %乘除类
+ -加减
<< >>移位
&按位与
^ |异或、或
== != > < >= <= is in比较/身份/成员
not逻辑非
and逻辑与
低or逻辑或
print(2 + 3 * 4)        # 14(先乘后加)
print(True or False and False)   # True(and 优先级高于 or)
# 等价 True or (False and False)

# 不要靠背优先级!复杂表达式请主动加括号,既正确又易读
x = 2 + 3 * 4 ** 2             # 50:** → * → +
y = 2 + (3 * (4 ** 2))         # 50,一目了然

工程建议:能用括号明确意图时就加括号。代码是写给人看的,不要让同事(以及三个月后的自己)去背优先级表。

9本章小结与练习

📌 关键结论

  • / 总返回 float;// 向下取整,负数方向要小心。
  • 链式比较 0 <= x < 100 是 Python 招牌写法。
  • and/or 会短路,并返回参与运算的对象本身;not 返回布尔值。
  • 比值用 ==,判空用 is None,判包含用 in。
  • Python 没有 ++/--;三元表达式是"值 if 条件 else 值"。
练习1:print(0 or 5 and 3) 输出什么?
输出 3。and 优先级高于 or,先算 5 and 3 → 3(5 为真,返回后者);再算 0 or 3 → 3(0 为假,返回后者 3)。
练习2:不使用 if,一行代码判断变量 n 是否为 0~100(含)之间的偶数。
print(0 <= n <= 100 and n % 2 == 0)。链式比较判断区间,% 判奇偶,and 组合。
练习3:解释为什么 [] and 1/0 不会触发除零错误,而 [] or 1/0 会。
and 左操作数 [] 为假,结果已确定为假,右侧 1/0 被短路不执行,所以返回 [];or 左操作数为假,必须计算右侧才能决定结果,于是执行 1/0 抛出 ZeroDivisionError。