Effective Python 条款 10 :海象运算符_=
- [Bilibili 同步视频](#Bilibili 同步视频)
- [🧊 传统写法的痛点:多余的临时变量](#🧊 传统写法的痛点:多余的临时变量)
- [✨海象运算符登场,把赋值放进 if 条件](#✨海象运算符登场,把赋值放进 if 条件)
- [🥤模拟 switch‑case,消灭多层嵌套 if](#🥤模拟 switch‑case,消灭多层嵌套 if)
- [🔁模拟 do‑while 循环,消除重复调用](#🔁模拟 do‑while 循环,消除重复调用)
- ⚠️海象运算符避坑指南
- 📝总结要点
摘自《Effective Python》第 10 条:用赋值表达式减少重复代码
Python3.8 版本正式登场的海象运算符
:=,很多同学初见它一脸懵:这冒号加等号到底是干嘛的?长得像海象的眼睛和獠牙,因此得名海象操作符(walrus operator)。
很多刚接触 Python 的开发者,会混淆普通赋值=和海象运算符:=。
-
a = b:赋值语句,只完成赋值,语句本身没有返回值,不能嵌入 if、while 条件当中。 -
a := b:赋值表达式 ,既把b的值赋值给变量a,同时表达式整体返回赋值后的结果。
简单一句话总结区别:普通赋值是一条语句,海象赋值是有返回结果的表达式 。正是这个特性,让我们可以把赋值动作直接塞进if、while、elif的条件判断里,消除大量重复变量定义、重复函数调用。
Bilibili 同步视频
🧊 传统写法的痛点:多余的临时变量
我们拿书中果汁店的业务场景举例:我们有一个存储库存的字典fresh_fruit,我们要读取柠檬库存,如果库存大于 0 就制作柠檬汁,否则提示缺货。
传统 Python 写法:
python
fresh_fruit = {
'apple': 10,
'banana': 8,
'lemon': 5,
}
def make_lemonade(count):
"""制作柠檬汁"""
print(f"制作柠檬汁,消耗柠檬:{count}")
def out_of_stock():
"""缺货处理"""
print("原料不足,缺货!")
# 传统写法
count = fresh_fruit.get('lemon', 0)
if count:
make_lemonade(count)
else:
out_of_stock()
这段代码逻辑没问题,但是有个小瑕疵:count变量定义在 if 外部。这个变量仅仅 if 分支需要,else 分支完全不用它。但代码阅读者第一眼会误以为 count 是整个作用域都要复用的核心变量,造成理解负担。现实项目中这种 "先赋值、再判断" 的模式遍地都是。
很多其他编程语言同样会遇到这个问题,我们看一段等价 C++ 代码,同样需要提前定义临时变量:
cpp
#include <iostream>
#include <unordered_map>
using namespace std;
void make_lemonade(int count) {
cout << "制作柠檬汁,消耗柠檬:" << count << endl;
}
void out_of_stock() {
cout << "原料不足,缺货!" << endl;
}
int main() {
unordered_map<string, int> fresh_fruit{
{"apple", 10},
{"banana", 8},
{"lemon",5}
};
// 需要提前声明临时变量lemon_cnt
int lemon_cnt = 0;
auto iter = fresh_fruit.find("lemon");
if(iter != fresh_fruit.end()){
lemon_cnt = iter->second;
}
if(lemon_cnt){
make_lemonade(lemon_cnt);
}else{
out_of_stock();
}
return 0;
}
C++17 之后引入了if 初始化语句语法缓解该问题,但写法依然繁琐。而 Python 海象运算符提供另一种简洁方案。
✨海象运算符登场,把赋值放进 if 条件
改造上面 Python 代码,使用:=:
python
fresh_fruit = {
'apple': 10,
'banana': 8,
'lemon': 5,
}
def make_lemonade(count):
print(f"制作柠檬汁,消耗柠檬:{count}")
def out_of_stock():
print("原料不足,缺货!")
# 海象运算符版本
if count := fresh_fruit.get('lemon', 0):
make_lemonade(count)
else:
out_of_stock()
这里执行流程:
-
执行
fresh_fruit.get('lemon',0)拿到库存; -
将结果赋值给
count; -
将 count 的值作为 if 条件表达式结果,做布尔判断。
变量count就在 if 条件处诞生,阅读代码一眼就能看懂:count 仅仅服务于这个 if 判断,没有多余的前置变量。
📌注意!带比较运算时,必须加括号
上面例子直接拿赋值表达式本身做布尔判断,不需要括号。但如果赋值之后还要做大小比较(比如苹果汁需要至少 4 个苹果),必须用括号包裹整个海象表达式!
❌错误写法
python
# 语法错误!优先级问题
if count := fresh_fruit.get("apple", 0) >=4:
...
✅正确写法
python
def make_cider(count):
print(f"制作苹果汁,消耗苹果:{count}")
# 外层做 >=4 的比较,内部海象表达式加括号
if (count := fresh_fruit.get("apple", 0)) >=4:
make_cider(count)
else:
out_of_stock()
原理:运算符优先级,
>=优先级高于:=,不加括号会先执行0 >=4得到布尔值,再把布尔值赋值给 count,逻辑完全错乱。这点踩坑人非常多!
🥤模拟 switch‑case,消灭多层嵌套 if
Python 直到 3.10 才正式推出match‑case模式匹配,在旧版本中,大家写多分支经常写出 "金字塔缩进地狱",一层 if 套一层 else,可读性雪崩。
传统嵌套版本,缩进越陷越深:
python
# 丑陋多层嵌套
count = fresh_fruit.get('banana', 0)
if count >=2:
pieces = slice_bananas(count)
to_enjoy = make_smoothies(pieces)
else:
count = fresh_fruit.get('apple', 0)
if count >=4:
to_enjoy = make_cider(count)
else:
count = fresh_fruit.get('lemon',0)
if count:
to_enjoy = make_lemonade(count)
else:
to_enjoy = "Nothing"
利用海象运算符 +elif,直接打平嵌套层级,代码瞬间清爽:
python
class OutOfBananas(Exception):
pass
def slice_bananas(count):
return count
def make_smoothies(pieces):
return f"香蕉冰沙,份数:{pieces}"
# 海象打平嵌套,模拟switch/case
if (count := fresh_fruit.get('banana', 0)) >= 2:
pieces = slice_bananas(count)
to_enjoy = make_smoothies(pieces)
elif (count := fresh_fruit.get('apple',0)) >=4:
to_enjoy = make_cider(count)
elif count := fresh_fruit.get('lemon',0):
to_enjoy = make_lemonade(count)
else:
to_enjoy = "Nothing"
print(to_enjoy)
不再一层一层向内缩进,分支逻辑平铺展开,每个分支内部获取自己需要的变量,可读性大幅提升。
🔁模拟 do‑while 循环,消除重复调用
Python 原生没有 do‑while 循环 。do‑while 特点:先执行一次循环体,再判断退出条件。
业务场景:不停采摘水果榨汁,直到摘出来的水果为空就停止。
传统写法要写两次pick_fruit(),一次循环前初始化,一次循环末尾更新,重复代码非常烦人:
python
def pick_fruit():
"""模拟采摘水果,返回库存字典,空代表采摘结束"""
import random
num = random.randint(0,3)
if num == 0:
return None
return {"apple": num}
def make_juice(fruit, cnt):
return [f"{fruit}果汁x{cnt}"]
bottles = []
fresh_fruit = pick_fruit() # 第一次调用
while fresh_fruit:
for fruit, count in fresh_fruit.items():
batch = make_juice(fruit, count)
bottles.extend(batch)
fresh_fruit = pick_fruit() # 重复第二次调用
print(bottles)
有些开发者会使用while True + break的半循环(loop‑and‑a‑half)模式规避重复,但无限循环 + break,逻辑比较隐晦:
python
bottles = []
while True:
fresh_fruit = pick_fruit()
if not fresh_fruit:
break
for fruit, count in fresh_fruit.items():
batch = make_juice(fruit, count)
bottles.extend(batch)
✨海象运算符终极简化版本!在 while 条件内部完成赋值 + 判断,只调用一次pick_fruit()
python
bottles = []
# 在while条件中完成赋值与判空
while fresh_fruit := pick_fruit():
for fruit, count in fresh_fruit.items():
batch = make_juice(fruit, count)
bottles.extend(batch)
print(bottles)
一行搞定赋值 + 循环终止判断,没有重复函数调用,也不需要 while True+break 的魔法写法,逻辑直白。
补充 C++ do‑while 对照参考,C++ 原生就支持 do while 语法,不需要额外技巧:
cpp
#include <iostream>
using namespace std;
int get_next(){
static int x = 5;
return x--;
}
int main(){
int val;
// C++原生do while,先执行,后判断
do{
val = get_next();
cout << "value:" << val << endl;
}while(val > 0);
return 0;
}
⚠️海象运算符避坑指南
-
区分 **
=与:=**:=是语句,不能放条件;:=是表达式,可以放 if/while/elif 条件。千万不要写混。 -
有比较运算符的时候记得加括号 :
if (x := func()) > 10:,漏掉括号是高频 bug 来源。 -
不要过度滥用 。不要为了少写一行代码到处堆砌
:=。如果会让逻辑变得晦涩难懂,那就老老实实拆分变量。它的目标是消除重复代码,而不是追求代码行数越少越好。 -
Python 版本限制:
:=从Python3.8才支持,低版本运行直接报语法错误。
📝总结要点
-
海象运算符
:=实现赋值表达式,赋值同时返回值,可以嵌入 if、while 条件,消除重复赋值、重复函数调用; -
如果赋值表达式还要参与大小比较运算,必须使用圆括号包裹;
-
可以优雅模拟
switch‑case(打平多层 if 嵌套)、do‑while循环逻辑; -
工具是为可读性服务,如果使用之后代码更难读懂,就不要强行使用。

写代码不是追求越短越好,而是让后来阅读代码的人一眼看懂你的意图,海象运算符正是为此而生。