04_Python运算符、表达式与类型转换
Python运算符、表达式与类型转换
你有没有想过,同样一个中缀表达式 3 + 2 * 4,为什么结果是 11 而不是 20?你在小学可能背过"先乘除后加减",但计算机凭什么也遵守这个规则?这份规则在编程里叫运算符优先级——它是语言设计者写进 Python 解释器的硬约定。
但运算符远不止加减乘除。Python 里有一套比你想象中丰富得多的运算符体系:能让你写出 0 <= score <= 100 这样优雅判断的链式比较,能让代码行数减半的海象运算符 :=,还有利用短路求值写出更安全代码的逻辑运算符……
这篇把 Python 运算符从头到尾讲清楚。看完之后,你会对"一个表达式到底怎么算"有清晰的认识。
算术运算符:不止加减乘除
七个算术运算符
a, b = 10, 3
print(a + b) # 13 加法
print(a - b) # 7 减法
print(a * b) # 30 乘法
print(a / b) # 3.3333333333333335 真除法,结果永远是 float
print(a // b) # 3 整除(地板除),向下取整
print(a % b) # 1 取余(模运算)
print(a ** b) # 1000 幂运算,10 的 3 次方
/ 和 // 的区别是高频考点也是高频踩坑点:
print(5 / 2) # 2.5 ——真除法,始终返回浮点数
print(5 // 2) # 2 ——整除,向负无穷方向取整
print(-5 // 2) # -3 ——注意!不是 -2,是 -3(向下取整)
很多人直觉上以为 -5 // 2 = -2(向零取整),但 Python 的 // 是向下取整,-2.5 向下是 -3。如果你需要向零取整,用 int(a / b)。
取余运算的妙用
% 取余(也叫模运算)看似简单,实际有很多巧妙的用途:
# 判断奇偶
num = 7
if num % 2 == 0:
print("偶数")
else:
print("奇数")
# 循环往复(比如 0, 1, 2, 0, 1, 2... 的循环)
for i in range(10):
position = i % 3
print(f"i={i}, position={position}")
# 提取个位数
print(12345 % 10) # 5
print(12345 % 100) # 45
# 判断闰年(能被 4 整除但不能被 100 整除,或能被 400 整除)
year = 2024
is_leap = (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)
print(f"{year}是闰年:{is_leap}")
幂运算和根号
# 幂运算
print(2 ** 3) # 8
print(16 ** 0.5) # 4.0 ——开平方
print(8 ** (1/3)) # 2.0 ——开立方
# 超大数
print(2 ** 100) # 1267650600228229401496703205376
# Python 的整数没有上限,这个 31 位的数字轻松搞定

图4-1 Python 运算符四大分类:算术、比较、逻辑、赋值,以及各类运算符的符号和用途总览。
比较运算符:让程序学会判断
比较运算符的结果是一个布尔值——非 True 即 False。
a, b = 10, 3
print(a == b) # False 等于
print(a != b) # True 不等于
print(a > b) # True 大于
print(a < b) # False 小于
print(a >= b) # True 大于等于
print(a <= b) # False 小于等于
Python 独有的链式比较
这是让 Python 程序员骄傲的语法之一。在大多数语言里,你要判断一个数是否在区间内,需要这样写:
// Java 写法
if (0 <= score && score <= 100) { ... }
而在 Python 里,你可以直接:
if 0 <= score <= 100:
print("成绩有效")
链式比较不只是好看——它更高效,因为中间的表达式只计算一次。你可以任意连接:
a, b, c, d = 1, 3, 5, 7
print(a < b < c < d) # True
print(a < b > c < d) # False(b > c 不成立,虽然 a < b 成立)
== 和 is 的区别
这是初学者必问的问题。简单说:
==比较值是否相等is比较是否为同一个对象(内存地址是否相同)
a = [1, 2, 3]
b = [1, 2, 3]
c = a
print(a == b) # True ——两个列表值相同
print(a is b) # False ——但是在内存里是两块独立的区域
print(a is c) # True ——c 和 a 指向同一块内存
对于小整数(-5 到 256),Python 会做缓存,所以 is 和 == 可能结果一致——但不要依赖这个行为。除非刻意比较对象身份(比如 is None),否则一律用 ==。
逻辑运算符:并且、或者、取反
基本用法
age = 20
score = 85
# and:两边都为真 → 真
print(age >= 18 and score >= 60) # True
# or:至少一边为真 → 真
print(age < 18 or score >= 90) # False
# not:取反
print(not (age < 18)) # True
短路求值——一种编程技巧
短路求值是指:逻辑表达式中一旦结果确定,剩余部分就不再执行。这不只是性能优化,更是一种可以主动利用的编程模式:
# 短路求值用在数据校验上
data = {"name": "小明"}
# 先判断键存在,再取值——如果键不存在,后面不会执行,避免了 KeyError
if "age" in data and data["age"] >= 18:
print("已成年")
# or 的短路:提供默认值
name = ""
display = name or "匿名用户" # name 是空字符串(假值),所以取后面的默认值
print(display) # "匿名用户"
# 更常见的默认值模式
config = {}
timeout = config.get("timeout") or 30 # 如果配置里没有,默认 30 秒
注意短路求值的一个陷阱:or 的默认值模式在 0、False、空字符串等假值上会出问题:
count = 0
result = count or 10 # 你可能期望 0,但得到的是 10!因为 0 是假值
print(result) # 10
# 正确做法:显式检查 None
result = count if count is not None else 10
print(result) # 0
赋值运算符:不只是 =
复合赋值运算符
x = 10
x += 3 # x = x + 3 → 13
x -= 2 # x = x - 2 → 11
x *= 4 # x = x * 4 → 44
x /= 2 # x = x / 2 → 22.0
x //= 3 # x = x // 3 → 7.0
x %= 5 # x = x % 5 → 2.0
x **= 3 # x = x ** 3 → 8.0
它们不是新概念——只是 x = x + 3 的简写。Python 的"一切运算符都可以和等号组合"的规则让代码更紧凑。
海象运算符 :=(Python 3.8+)
这是近年 Python 最重要的语法新增之一。它让你在表达式内部做赋值。
# 传统写法:读取一行,判断是否为空,再做处理
line = input("请输入:")
while line != "quit":
print(f"你输入了:{line}")
line = input("请输入:")
# 用海象运算符:赋值和判断二合一
while (line := input("请输入:")) != "quit":
print(f"你输入了:{line}")
更常见的场景是列表推导和条件判断中的复用:
# 计算字符串长度,只在长度大于 3 时做处理
text = "Python"
if (n := len(text)) > 3:
print(f"字符串有 {n} 个字符,符合要求")
# 在列表推导中使用
data = ["hello", "world", "a", "bc", "test"]
# 取长度大于 2 的字符串,同时记录长度
result = [(word, length) for word in data if (length := len(word)) > 2]
print(result) # [('hello', 5), ('world', 5), ('test', 4)]
海象运算符让代码更紧凑,但也可能降低可读性。一个简单原则:如果用了它之后代码变得难读,就别用。它最适合的场景是 while 循环和 if 条件中的"边判断边赋值"。

图4-2 类型转换示意图:int()、float()、str()、bool() 四种显式转换函数,以及字符串与数字相互转换的规则。
位运算符:与硬件对话的桥梁
位运算符直接操作二进制位。初学者可能觉得用不到,但了解它们能让你理解计算机的底层逻辑。而且某些场景下(权限管理、状态标志、优化计算),位运算是最优雅的解决方案。
六个位运算符
a, b = 0b1100, 0b1010 # 12 和 10
print(f"a = {a:04b}") # a = 1100
print(f"b = {b:04b}") # b = 1010
print(f"a & b = {a & b:04b}") # 1000 按位与:两位都为1才为1
print(f"a | b = {a | b:04b}") # 1110 按位或:至少一位为1就为1
print(f"a ^ b = {a ^ b:04b}") # 0110 按位异或:两位不同为1
print(f"~a = {~a:04b}") # ... 按位取反(涉及补码,比较复杂)
print(f"a << 1 = {a << 1:04b}") # 11000 左移:所有位向左移动,右边补0
print(f"a >> 1 = {a >> 1:04b}") # 0110 右移:所有位向右移动
位运算的实用场景
# 场景一:用位掩码管理权限
READ = 0b001 # 1
WRITE = 0b010 # 2
EXECUTE = 0b100 # 4
# 给用户赋予"读"和"写"权限
user_permission = READ | WRITE # 0b011 = 3
# 检查用户是否有"写"权限
has_write = (user_permission & WRITE) != 0
print(f"有写入权限:{has_write}") # True
# 场景二:快速判断奇偶
num = 7
if num & 1:
print("奇数") # 二进制末位为 1 就是奇数
else:
print("偶数")
# 场景三:快速乘以/除以 2 的幂
print(8 << 1) # 16 相当于 8 * 2
print(8 << 3) # 64 相当于 8 * 8
print(64 >> 2) # 16 相当于 64 / 4
初学阶段位运算不需要完全掌握。你只需要知道有这个东西存在,当以后在框架源码或算法题里看到 &、|、<< 时不会懵掉。
为什么位运算会存在?因为它直接操作二进制位,速度是所有运算中最快的。在需要极高性能的场合——图形渲染、加密算法、网络协议解析、嵌入式系统——位运算是主力工具。日常业务代码中用到位运算的机会不多,但每用一次,往往都是因为常规方式太慢或太笨重。
另外提一句:位运算中 << 1 等价于 * 2,>> 1 等价于 // 2。在性能敏感的代码中,有人会故意用位移代替乘除,因为位移比乘除快一个数量级。但在普通业务代码中不建议这么做——* 2 比 << 1 好读太多,而现代 CPU 做乘除的速度已经足够快了。可读性优先于微小的性能提升,这条原则适用于绝大多数编程场景。
运算符优先级:先算谁、后算谁
计算机和小学数学一样——乘除优先于加减。但当运算符种类多起来时,优先级就成了一个需要了解的系统。
Python 运算符优先级从高到低(只列常用的):
** 幂运算(最高)
+x, -x, ~x 正负号、按位取反
*, /, //, % 乘除整除取余
+, - 加减
<<, >> 位移
& 按位与
^ 按位异或
| 按位或
==, !=, >, <, >=, <=, is, is not, in, not in 比较
not 逻辑非
and 逻辑与
or 逻辑或(最低)
if-else 条件表达式
:= 海象运算符
不用背这个表。写代码时如果你不确定优先级,直接加括号。括号里的内容总是先算。
# 不确定 and 和 or 谁优先?加括号就行了
if (age >= 18 and has_ticket) or is_vip:
print("可以入场")
# 而不是赌运算符的优先级
if age >= 18 and has_ticket or is_vip:
# 这行含义模糊,容易出 bug
记住一句话:代码是写给人读的,括号是给人看的。多打两个括号不会让程序变慢,但能让你的意图变得无比清晰。
在绝大��数情况下,你不需要依赖优先级表来写代码。如果一段表达式让你犹豫"先算哪个",那就加括号。老程序员和新手的区别之一就是:新手炫技写一长串无括号的表达式,老手用括号让每个计算步骤清晰如画。
一个有用的心理模型:把复杂表达式想象成数学公式的拆解。就像你不会把 (a² + b²)/(a - b) × √(c + d) 写成一行密密麻麻的符号一样,在 Python 里也应该把复杂计算拆成多步,给每一步起一个好名字:

图4-3 运算符优先级示意:从幂运算到逻辑或的优先级梯子,以及推荐使用括号明确计算意图。
表达式和语句——你可能混淆的两个概念
初学者经常把"表达式"和"语句"混着用,但它们有明确的区别。
**表达式(Expression)**是一段能"求出值"的代码:
3 + 5 # 求值为 8
x > 10 # 求值为 True 或 False
"Hello" + "World" # 求值为 "HelloWorld"
len([1, 2, 3]) # 求值为 3
**语句(Statement)**是一个"执行动作"的完整指令,不一定有返回值:
x = 10 # 赋值语句
if x > 5: # if 语句
print("大于5") # 调用语句
for i in range(3): # for 语句
pass
简单记忆:能放到 print() 里的就是表达式。能放到赋值等号右边的是表达式。if、for、def 这些关键词开头的是语句。
Python 的设计哲学之一是"一切皆对象",所以很多在其他语言里是语句的东西在 Python 里也是表达式——这个特点在函数式编程和生成器推导式中体现得尤为明显,第 15 篇会展开。
综合实战:用运算符写一个商场折扣计算器
把学到的运算符综合起来用,写一个真实的折扣计算逻辑:
def calculate_discount():
"""商场折扣计算器"""
print("===== 商场折扣计算器 =====")
# 输入商品信息
original_price = float(input("商品原价(元):"))
quantity = int(input("购买数量:"))
# 是否满足特殊条件
is_member = input("是会员吗?(y/n):").strip().lower() == 'y'
is_holiday_promo = input("是否节日促销?(y/n):").strip().lower() == 'y'
# 计算基础金额
subtotal = original_price * quantity
# 折扣规则(注意:实际业务中这些规则可能更复杂)
discount = 0.0
# 数量折扣:买够 5 件打 95 折,10 件打 9 折
if quantity >= 10:
discount = max(discount, 0.10)
elif quantity >= 5:
discount = max(discount, 0.05)
# 会员折扣:会员满 200 元额外 97 折
if is_member and subtotal >= 200:
discount = max(discount, 0.03) # 注意:这里是叠加规则简化
# 节日促销:直接 9 折,取最低折扣
if is_holiday_promo:
discount = max(discount, 0.10)
# 计算最终价格
final_price = subtotal * (1 - discount)
saved = subtotal - final_price
# 输出结果
print()
print(f"商品原价:¥{original_price:.2f} × {quantity} = ¥{subtotal:.2f}")
print(f"折扣率:{discount:.0%}")
print(f"实付金额:¥{final_price:.2f}")
print(f"节省:¥{saved:.2f}")
# 额外判断
if saved == 0:
print("本次没有享受到折扣,建议办理会员卡。")
elif saved > 50:
print("优惠力度很不错!")
return final_price
calculate_discount()
这个例子覆盖了:算术运算符(计算金额)、比较运算符(判断数量和金额阈值)、逻辑运算符(会员且满额)、赋值运算符、类型转换(字符串转数字)。试着运行它,改改折扣规则,感受运算符在实际业务中的协同作用。
深入理解比较运算符——你可能忽略的几个细节
字符串也能比较大小吗
能。字符串比较基于字符的 Unicode 码位,按字典序逐个字符比较:
print("apple" < "banana") # True 按字母顺序
print("abc" < "abd") # True 前两位相同,第三位 c < d
print("A" < "a") # True 大写字母码位比小写小
# 数字字符串的比较——注意陷阱!
print("100" < "20") # True!因为 '1' < '2',不是数值比较!
print(100 < 20) # False 数值比较当然不同
浮点数比较的正确方式
# 错误:直接 == 比较
print(0.1 + 0.2 == 0.3) # False!
# 正确:使用 math.isclose
import math
print(math.isclose(0.1 + 0.2, 0.3)) # True
print(math.isclose(0.1 + 0.2, 0.3, rel_tol=1e-9)) # True,指定相对容差
# 或者设定容许范围
EPSILON = 1e-9
print(abs((0.1 + 0.2) - 0.3) < EPSILON) # True
深入理解逻辑运算符——and 和 or 的真实返回值
很多人以为 and 和 or 总是返回 True 或 False。实际上,它们返回的是参与运算的其中一个对象:
# and:如果第一个为假,返回第一个;否则返回第二个
print(0 and 42) # 0(第一个是假值,直接返回)
print(3 and 42) # 42(第一个是真值,返回第二个)
print("" and "hello") # ""(空字符串是假值)
# or:如果第一个为真,返回第一个;否则返回第二个
print(0 or 42) # 42(第一个是假值,返回第二个)
print(3 or 42) # 3(第一个是真值,直接返回,不看第二个)
print("" or "hello") # "hello"(空字符串是假值,返回第二个)
这个特性可以用来写非常简洁的代码:
# 设置默认值(但要小心假值陷阱,前面已提过)
username = input_name or "匿名用户"
# 条件执行(不推荐滥用,可读性重要)
result = is_valid and process_data()
# 等价于:result = process_data() if is_valid else False
逻辑运算符的多重组合
# 优先级:not > and > or
# 当混合使用时,建议加括号让意图明确
a, b, c = True, False, True
# 不清晰(依赖于优先级)
result = a and b or c # True
# 清晰(意图明确)
result = (a and b) or c # True
赋值运算符的更多模式
多重赋值和星号解包
# 常规:交换两个变量——Python 不需要临时变量!
a, b = 10, 20
a, b = b, a
print(a, b) # 20 10
# 星号解包采集剩余
first, second, *others = [1, 2, 3, 4, 5]
print(first) # 1
print(second) # 2
print(others) # [3, 4, 5]
# 两边都可用星号(Python 3.9+ 不支持,3.11+ 才支持多个星号)
# 采集中间部分
first, *middle, last = [1, 2, 3, 4, 5]
print(middle) # [2, 3, 4]
海象运算符的实战场景
再举几个 := 让你真正感受到它有多方便的例子:
# 场景一:while 循环中读取文件(后面第12篇会用到)
# 不用 :=
line = file.readline()
while line:
process(line)
line = file.readline()
# 用 :=
while (line := file.readline()):
process(line)
# 场景二:正则匹配同时判断和提取(后面会学 re 模块)
import re
text = "我的电话是 13800138000"
# 不用 :=
match = re.search(r"\d{11}", text)
if match:
phone = match.group()
print(phone)
# 用 :=
if (match := re.search(r"\d{11}", text)):
print(match.group())
# 场景三:在列表推导中复用计算
data = [3.14, 2.71, 1.41, 99.9]
# 取平方大于 10 的数,同时记录平方值
results = [(x, sq) for x in data if (sq := x ** 2) > 10]
print(results) # [(3.14, 9.8596), (2.71, 7.3441), (99.9, 9980.01)]
海象运算符不是必须用的——所有场景都能用传统写法替代。但它在某些地方能显著减少代码行数和重复计算,是值得放进工具箱的利器。
位运算的更多实用技巧
颜色值处理
Web 开发中常见的十六进制颜色值,可以用位运算来提取 RGB 分量:
# #FF8040 → R=255, G=128, B=64
color = 0xFF8040
r = (color >> 16) & 0xFF # 255
g = (color >> 8) & 0xFF # 128
b = color & 0xFF # 64
print(f"R={r}, G={g}, B={b}")
# 反过来,用 RGB 拼接成颜色值
r, g, b = 100, 200, 50
color = (r << 16) | (g << 8) | b
print(f"#{color:06X}") # #64C832
状态标志位
用一个整数来存储多个开关状态,比用多个布尔变量更紧凑:
# 定义状态
STATUS_IDLE = 0b0000 # 0
STATUS_RUNNING = 0b0001 # 1
STATUS_PAUSED = 0b0010 # 2
STATUS_ERROR = 0b0100 # 4
STATUS_COMPLETED = 0b1000 # 8
# 设置状态
state = STATUS_RUNNING | STATUS_PAUSED # 同时处于运行和暂停状态
# 应该是不合理的,但演示了如何组合标志
# 切换状态:打开
state |= STATUS_ERROR
# 切换状态:关闭
state &= ~STATUS_ERROR
# 检查状态
is_running = (state & STATUS_RUNNING) != 0
print(f"运行中:{is_running}")
这种模式在底层系统编程、游戏开发、协议解析中非常常见。Python 程序员用到它的频率不高,但了解它能让你看懂更多代码。
用运算符实现常见的数学和业务公式
把运算符应用到实际问题中,看看它们能解决什么。
复利计算
# 复利公式:A = P * (1 + r)^n
# P = 本金, r = 年利率, n = 年数
principal = 10000 # 本金 1 万元
rate = 0.03 # 年利率 3%
years = 5 # 5 年
amount = principal * (1 + rate) ** years
print(f"{years} 年后本息合计:¥{amount:.2f}")
# 10000 * (1.03)^5 ≈ 11592.74
成绩统计
scores = [85, 92, 78, 95, 88, 72, 99, 60]
# 各种统计指标
total = sum(scores) # 求和
count = len(scores) # 计数
average = total / count # 平均
max_score = max(scores) # 最高
min_score = min(scores) # 最低
pass_rate = sum(1 for s in scores if s >= 60) / count # 及格率
print(f"总人数:{count}")
print(f"平均分:{average:.1f}")
print(f"最高分:{max_score}")
print(f"最低分:{min_score}")
print(f"及格率:{pass_rate:.1%}")
分段定价
# 快递分段计费:首重 1kg 内 10 元,续重每 kg 加 3 元
def calculate_shipping(weight):
first_weight, first_price = 1, 10
extra_price_per_kg = 3
if weight <= first_weight:
return first_price
else:
return first_price + (weight - first_weight) * extra_price_per_kg
for w in [0.5, 1.0, 1.2, 3.5, 10.0]:
print(f"重量 {w}kg → 运费 ¥{calculate_shipping(w):.2f}")
类型转换的边界和陷阱
类型转换虽然是上篇的内容,但其本质是"数据的重新解释",与运算符配合使用时有几个容易忽略的边界情况:
# int() 会截断,不会四舍五入
print(int(3.9)) # 3,不是 4!
print(int(-3.9)) # -3,不是 -4!
# float 转 int 的正确四舍五入
print(round(3.9)) # 4
# bool 其实是 int 的子类!
print(True + True) # 2 (True 等价于 1)
print(True + False) # 1
print(isinstance(True, int)) # True ——bool 是 int 的子类!
# 这个特性在计数场景特别方便
passed = [True, False, True, True, False]
print(f"通过人数:{sum(passed)}") # 3 True=1, False=0
常见错误和调试技巧
| 错误 | 原因 | 解决 |
|---|---|---|
5/0 → ZeroDivisionError | 分母为 0 | 除法前判断 if b != 0: |
"3" + 2 → TypeError | 字符串和数字混用 | 统一类型:int("3") + 2 |
= 和 == 搞混 | = 赋值,== 比较 | if 里永远用 == |
a = b = [] 共享引用 | 两个变量指向同一个空列表 | 分别赋值或用 .copy() |
3 ^ 2 不等于 9 | ^ 是异或不是幂运算 | 用 ** 做幂运算 |
| 链式比较放反了 | 100 <= score <= 0 永远假 | 小值在左:0 <= score <= 100 |
动手做
- 写一个程序,输入一个三位整数,用
//和%提取它的百位、十位、个位数字。例如输入 357,输出 “百位=3, 十位=5, 个位=7”。 - 用链式比较
0 <= score <= 100判断用户输入的成绩是否有效。分别输入 -5、60、120、85 测试四个边界。 - 写一个程序,用海象运算符
:=在while循环中接收用户输入,输入 “quit” 时退出,否则打印输入内容的长度。 - 用位运算实现一个"权限系统":读=4、写=2、执行=1。给一个变量赋予读写权限,然后分别检查它是否有读、写、执行权限。再尝试移除写权限后重新检查。
本篇要点回顾:
- Python 有算术(
+ - * / // % **)、比较(== != > < >= <=)、逻辑(and or not)、位运算(& | ^ ~ << >>)四大类运算符 - 链式比较是 Python 的特色:
0 <= x <= 100 - 短路求值可以主动利用来写更安全的判断
- 海象运算符
:=在 while 和 if 中同时赋值和判断 - 不确定优先级就加括号,括号不花钱但值千金
==比的是值,is比的是身份——除非和None比,否则用==
下一篇我们进入流程控制的第一站——分支结构 if/elif/else,让你的程序学会"在岔路口做选择"。
operator 模块和 math 模块——内置的运算符工具箱
当你需要把运算符当成函数来用时(比如传给 map()、reduce() 等高级函数),operator 模块就派上了用场:
import operator
# 运算符当函数用
print(operator.add(3, 5)) # 8 ——等价于 3 + 5
print(operator.mul(3, 5)) # 15 ——等价于 3 * 5
print(operator.pow(2, 10)) # 1024 ——等价于 2 ** 10
print(operator.eq(3, 5)) # False ——等价于 3 == 5
# 在高阶函数中使用(先感受一下)
from functools import reduce
numbers = [1, 2, 3, 4, 5]
product = reduce(operator.mul, numbers)
print(product) # 120 ——1*2*3*4*5
math 模块提供了更多数学功能:
import math
print(math.sqrt(16)) # 4.0 ——开平方
print(math.factorial(5)) # 120 ——5!
print(math.gcd(48, 18)) # 6 ——最大公约数
print(math.lcm(12, 18)) # 36 ——最小公倍数(Python 3.9+)
print(math.comb(5, 2)) # 10 ——组合数 C(5,2)
print(math.perm(5, 2)) # 20 ——排列数 P(5,2)
print(math.pi) # 3.141592653589793
print(math.e) # 2.718281828459045
print(math.ceil(3.1)) # 4 ——向上取整
print(math.floor(3.9)) # 3 ——向下取整
print(math.trunc(-3.9)) # -3 ——向零取整
注意 math.trunc() 和 int() 效果相同(向零截断),但与 math.floor() 在处理负数时不同:
print(math.floor(-3.1)) # -4 向下取整
print(math.trunc(-3.1)) # -3 向零取整
print(int(-3.1)) # -3 也是向零取整
运算符重载——给自定义对象赋予运算能力
这是稍微超前的内容(面向对象篇会详细讲),但提前种个印象也好。Python 允许你为自定义的类定义运算符行为:
class Vector:
"""二维向量,可以相加"""
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
"""定义 + 的行为"""
return Vector(self.x + other.x, self.y + other.y)
def __repr__(self):
return f"Vector({self.x}, {self.y})"
v1 = Vector(1, 2)
v2 = Vector(3, 4)
v3 = v1 + v2 # 调用了 __add__
print(v3) # Vector(4, 6)
print(v1 * 3) # 会报错——还没有定义 __mul__
这就是 Python 运算符的完整图景:标准运算符对所有内置类型都有效,而你可以通过定义特殊方法(__add__、__mul__、__eq__ 等)来让自定义类型也支持这些运算符。等你学到第 14 篇面向对象进阶时,会对这部分有更深入的理解。
练习:用运算符解决几个实际问题
以下练习请务必在 VS Code 里亲手完成。看懂了和写出来了之间的差距,比你想象的大。
练习一:BMI 计算器
BMI = 体重(kg) / 身高(m)^2。输入身高和体重,输出 BMI 值和体型判定:
- BMI < 18.5:偏瘦
- 18.5 <= BMI < 24:正常
- 24 <= BMI < 28:偏胖
- BMI >= 28:肥胖
要求:用链式比较写条件判断,BMI 保留一位小数。
练习二:密码强度检测器
输入一个密码,根据以下规则打分并给出强度评级:
- 长度 >= 8:+1 分
- 包含数字:+1 分
- 包含大写字母:+1 分
- 包含特殊字符(!@#$%^&*):+1 分
- 0~1 分:弱,2~3 分:中,4 分:强
提示:any(char.isdigit() for char in password) 可以判断是否包含数字。
练习三:闰年判断器
闰年规则:能被 4 整除但不能被 100 整除,或者能被 400 整除。用一行表达式(尽可能简洁)判断一个年份是否是闰年。
练习四:位运算权限系统
设计一个文件权限系统,支持读(R=4)、写(W=2)、执行(X=1)三种权限。实现以下功能:
- 给用户添加某项权限
- 删除用户的某项权限
- 检查用户是否有某项权限
- 显示用户权限的八进制表示(类似 Linux 的
chmod)
提示:
def has_permission(user_perm, perm):
return (user_perm & perm) != 0
def add_permission(user_perm, perm):
return user_perm | perm
def remove_permission(user_perm, perm):
return user_perm & ~perm
练习五:购物车总价计算
写一个程序,用户可以输入多个商品的价格(输入 q 结束),然后:
- 输出总价
- 如果总价 >= 200,打 9 折
- 如果总价 >= 500,打 8 折
- 输出最终应付金额
要求用海象运算符简化输入循环。
这些练习的目的不是让你写出"完美"的代码,而是让你在动手的过程中发现自己哪里不清楚。遇到问题就回翻对应的小节,或者打开 Python 交互模式试验一下——这是最有效的学习方式。
一些给你参考的实现思路
上面五个练习,这里给出练习二(密码强度)和练习四(权限系统)的参考实现。注意:编程题没有唯一答案,你的代码和下面不一样不代表你错了——只要运行结果符合要求就好。
练习二的参考:
def check_password_strength():
password = input("请输入密码:")
score = 0
if len(password) >= 8:
score += 1
print(f" +1 长度达标(≥8)")
else:
print(f" +0 长度不足(当前 {len(password)} 位)")
if any(c.isdigit() for c in password):
score += 1
print(f" +1 包含数字")
if any(c.isupper() for c in password):
score += 1
print(f" +1 包含大写字母")
if any(c in "!@#$%^&*" for c in password):
score += 1
print(f" +1 包含特殊字符")
levels = {0: "弱", 1: "弱", 2: "中", 3: "中", 4: "强"}
print(f"\n总得分:{score},密码强度:{levels.get(score, '未知')}")
# check_password_strength()
练习四的参考:
READ, WRITE, EXECUTE = 4, 2, 1
def show_perm(perm):
"""以类似 Linux ls -l 的形式显示权限"""
r = "r" if (perm & READ) else "-"
w = "w" if (perm & WRITE) else "-"
x = "x" if (perm & EXECUTE) else "-"
return f"{r}{w}{x}"
# 测试
user_perm = 0
user_perm |= READ | WRITE # 赋予读写权限
print(show_perm(user_perm)) # rw-
user_perm |= EXECUTE # 添加执行权限
print(show_perm(user_perm)) # rwx
user_perm &= ~WRITE # 移除写权限
print(show_perm(user_perm)) # r-x
一点建议:别纠结于记住所有运算符
这篇文章列了很多运算符——从算术到位运算,从海象到链式比较。你不用一次性全部记住。事实上,很多写了十年 Python 的程序员也不会经常用位运算或 operator 模块。
你应该记住的核心是:
+ - * / // % **七种算术运算== != > < >= <=六种比较and or not三种逻辑- 括号优先,不确定就加括号
剩下的——海象运算符、位运算、链式比较、operator 模块——知道它们存在,用到了回来查就行。编程不是在考场默写,是在工位上查文档。知道"有这个功能"比"背下所有用法"重要得多。
更多推荐



所有评论(0)