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 运算符四大分类:算术、比较、逻辑、赋值,以及各类运算符的符号和用途总览。

比较运算符:让程序学会判断

比较运算符的结果是一个布尔值——非 TrueFalse

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 的默认值模式在 0False、空字符串等假值上会出问题:

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() 里的就是表达式。能放到赋值等号右边的是表达式。iffordef 这些关键词开头的是语句。

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 的真实返回值

很多人以为 andor 总是返回 TrueFalse。实际上,它们返回的是参与运算的其中一个对象

# 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

动手做

  1. 写一个程序,输入一个三位整数,用 //% 提取它的百位、十位、个位数字。例如输入 357,输出 “百位=3, 十位=5, 个位=7”。
  2. 用链式比较 0 <= score <= 100 判断用户输入的成绩是否有效。分别输入 -5、60、120、85 测试四个边界。
  3. 写一个程序,用海象运算符 :=while 循环中接收用户输入,输入 “quit” 时退出,否则打印输入内容的长度。
  4. 用位运算实现一个"权限系统":读=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 模块——知道它们存在,用到了回来查就行。编程不是在考场默写,是在工位上查文档。知道"有这个功能"比"背下所有用法"重要得多。

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐