欢迎光临
我们一直在努力

Effective Python 条款 10 :海象运算符_=

Effective Python 条款 10 :海象运算符_=

  • Bilibili 同步视频
  • 🧊 传统写法的痛点:多余的临时变量
  • ✨海象运算符登场,把赋值放进 if 条件
    • 📌注意!带比较运算时,必须加括号
  • 🥤模拟 switch‑case,消灭多层嵌套 if
  • 🔁模拟 do‑while 循环,消除重复调用
  • ⚠️海象运算符避坑指南
  • 📝总结要点

摘自《Effective Python》第 10 条:用赋值表达式减少重复代码 Python3.8 版本正式登场的海象运算符 :=,很多同学初见它一脸懵:这冒号加等号到底是干嘛的?长得像海象的眼睛和獠牙,因此得名海象操作符(walrus operator)。

很多刚接触 Python 的开发者,会混淆普通赋值=和海象运算符:=。

  • a = b:赋值语句,只完成赋值,语句本身没有返回值,不能嵌入 if、while 条件当中。

  • a := b:赋值表达式,既把b的值赋值给变量a,同时表达式整体返回赋值后的结果。

简单一句话总结区别:普通赋值是一条语句,海象赋值是有返回结果的表达式。正是这个特性,让我们可以把赋值动作直接塞进if、while、elif的条件判断里,消除大量重复变量定义、重复函数调用。

Bilibili 同步视频

Effective Python 条款 10 :海象运算符_=

🧊 传统写法的痛点:多余的临时变量

我们拿书中果汁店的业务场景举例:我们有一个存储库存的字典fresh_fruit,我们要读取柠檬库存,如果库存大于 0 就制作柠檬汁,否则提示缺货。

传统 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++ 代码,同样需要提前定义临时变量:

#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 代码,使用:=:

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 个苹果),必须用括号包裹整个海象表达式!

    ❌错误写法

    # 语法错误!优先级问题
    if count := fresh_fruit.get("apple", 0) >=4:
    ...

    ✅正确写法

    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,可读性雪崩。

    传统嵌套版本,缩进越陷越深:

    # 丑陋多层嵌套
    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,直接打平嵌套层级,代码瞬间清爽:

    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(),一次循环前初始化,一次循环末尾更新,重复代码非常烦人:

    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,逻辑比较隐晦:

    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()

    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 语法,不需要额外技巧:

    #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循环逻辑;

  • 工具是为可读性服务,如果使用之后代码更难读懂,就不要强行使用。

  • Effective Python 条款 10 :海象运算符_=

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

    赞(0)
    未经允许不得转载:171主机测评 » Effective Python 条款 10 :海象运算符_=
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址