在 Python 中,赋值运算符不只是把一个值放进变量。它还承担着变量初始化、状态更新、批量绑定,以及在表达式中保存中间结果等任务。掌握这些写法,可以让代码更短,但更重要的是让状态变化更容易阅读和维护。
从初始化开始:让变量有明确的起点
最基本的赋值使用单个等号:
user_name = "Lin"
login_count = 0
is_active = True
等号的作用是把右侧表达式计算出的结果绑定到左侧名称。右侧可以是字面量、函数调用,也可以是更复杂的表达式:
price = 19.9
quantity = 3
total = price * quantity
print(f"{user_name}: {total:.2f}")
建议在变量第一次使用前完成初始化,尤其是在条件分支中。下面的写法可能在 has_discount 为 False 时使用一个尚未定义的变量:
# 不够稳健
if has_discount:
final_price = price * 0.9
print(final_price)
可以先给变量一个默认值,再根据条件更新它:
final_price = price
if has_discount:
final_price *= 0.9
print(final_price)
这种写法把变量的生命周期表达得更清楚,也避免了 UnboundLocalError 或 NameError。
批量赋值与解包:减少重复代码
Python 支持同时给多个变量赋值:
width, height = 1920, 1080
也可以利用解包交换两个变量,而不需要临时变量:
width, height = height, width
解包要求左右两侧的结构匹配。处理长度可能变化的数据时,可以使用星号收集剩余元素:
first, *middle, last = [10, 20, 30, 40, 50]
print(first) # 10
print(middle) # [20, 30, 40]
print(last) # 50
如果数据格式不稳定,直接解包可能抛出 ValueError。这时应先校验长度,或者使用更明确的索引和默认值逻辑,而不是为了追求简短而隐藏输入约束。
用增强赋值表达状态更新
增强赋值把运算和重新赋值合并在一起:
score = 10
score += 5
score *= 2
score -= 3
print(score) # 27
常见形式包括:
count += 1
balance -= payment
ratio *= factor
average /= sample_count
remainder %= divisor
它们适合表达“基于当前值更新状态”。对于列表,+= 还会体现出可变对象的行为差异:
items = ["book"]
alias = items
items += ["pen"]
print(items) # ['book', 'pen']
print(alias) # ['book', 'pen']
这里列表对象被原地扩展,alias 仍然指向同一个列表。相比之下,使用普通赋值可能创建新的列表对象:
items = ["book"]
alias = items
items = items + ["pen"]
print(items) # ['book', 'pen']
print(alias) # ['book']
因此,处理列表、字典等可变对象时,要明确自己需要的是原地修改还是创建新对象。
海象运算符:在条件中保存结果
海象运算符 := 可以在表达式中完成赋值。它适合“计算一次,同时判断或继续使用结果”的场景:
message = "Python makes assignment expressive"
if (length := len(message)) > 20:
print(f"消息长度为 {length},超过 20 个字符")
读取输入时,海象运算符可以避免重复调用:
# 运行后输入一行文本;输入空行结束
while (line := input("请输入内容:").strip()):
print(f"收到:{line}")
不过,海象运算符会增加表达式密度。若赋值和判断组合后难以一眼读懂,普通的两步写法通常更好:
line = input("请输入内容:").strip()
if line:
print(f"收到:{line}")
它尤其适合循环条件、正则匹配结果或昂贵计算结果需要立即复用的地方,不应为了少写一行代码而到处使用。
一个可运行的小例子
下面的程序演示了初始化、增强赋值、解包和海象运算符。保存为 assignment_demo.py 后即可运行:
from typing import Iterable
def summarize_scores(scores: Iterable[int]) -> tuple[int, float]:
total = 0
count = 0
for score in scores:
total += score
count += 1
average = total / count if count else 0.0
return total, average
passed, failed = 3, 1
passed += 2
failed += 1
total, average = summarize_scores([88, 92, 76, 100])
if (rounded_average := round(average, 1)) >= 90:
result = "优秀"
else:
result = "继续提升"
print(f"通过:{passed},未通过:{failed}")
print(f"总分:{total},平均分:{rounded_average},评价:{result}")
这个例子中,passed += 2 和 failed += 1 清楚地表示计数器更新;total, average = ... 使用解包接收函数返回值;rounded_average := ... 在判断时保存已经计算好的结果。
写稳健赋值时的检查清单
- 变量第一次使用前是否已经初始化?
- 条件分支是否覆盖了变量的所有使用路径?
- 多变量解包的输入长度是否可靠?
+=用在可变对象上时,是否确实需要原地修改?- 海象运算符是否让代码更容易阅读,而不是更难?
- 变量名是否表达了值的含义和单位,例如
timeout_seconds而不是含义模糊的timeout?
好的赋值代码不在于使用最多的语法,而在于清楚表达数据从哪里来、如何初始化,以及何时发生变化。对简单状态使用普通赋值,对累计和更新使用增强赋值,对结构化返回值使用解包;只有在能减少重复计算且不损害可读性时,才引入海象运算符。