目录
-
- Python 3.8 新特性:深入理解并掌握赋值表达式(The Walrus Operator)
- 1. 什么是赋值表达式?打破传统的“:=”
- 2. 核心应用场景:让代码更简洁、更高效
-
- 2.1 `while` 循环中的 `read()` 模式
- 2.2 列表推导式与 `walrus` 的威力
- 2.3 `if` 分支中的复杂匹配
- 3. 理解作用域:它不仅仅是“局部变量”
-
- 3.1 列表推导式的新作用域
- 3.2 循环与 `if` 块的作用域陷阱
- 4. 什么时候不应该使用赋值表达式?
- 5. 总结与展望
专栏导读
-
🌸 欢迎来到Python办公自动化专栏—Python处理办公问题,解放您的双手
-
🏳️🌈 个人博客主页:请点击——> 个人的博客主页 求收藏
-
🏳️🌈 Github主页:请点击——> Github主页 求Star⭐
-
🏳️🌈 知乎主页:请点击——> 知乎主页 求关注
-
🏳️🌈 CSDN博客主页:请点击——> CSDN的博客主页 求关注
-
👍 该系列文章专栏:请点击——>Python办公自动化专栏 求订阅
-
🕷 此外还有爬虫专栏:请点击——>Python爬虫基础专栏 求订阅
-
📕 此外还有python基础专栏:请点击——>Python基础学习专栏 求订阅
-
文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏
-
❤️ 欢迎各位佬关注! ❤️
🌸 欢迎来到Python办公自动化专栏—Python处理办公问题,解放您的双手
🏳️🌈 个人博客主页:请点击——> 个人的博客主页 求收藏
🏳️🌈 Github主页:请点击——> Github主页 求Star⭐
🏳️🌈 知乎主页:请点击——> 知乎主页 求关注
🏳️🌈 CSDN博客主页:请点击——> CSDN的博客主页 求关注
👍 该系列文章专栏:请点击——>Python办公自动化专栏 求订阅
🕷 此外还有爬虫专栏:请点击——>Python爬虫基础专栏 求订阅
📕 此外还有python基础专栏:请点击——>Python基础学习专栏 求订阅
文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏
❤️ 欢迎各位佬关注! ❤️
Python 3.8 新特性:深入理解并掌握赋值表达式(The Walrus Operator)
1. 什么是赋值表达式?打破传统的“:=”
在 Python 3.8 正式引入赋值表达式之前,我们习惯将赋值语句(=)严格区分于表达式。赋值语句用于改变变量状态,而表达式用于计算并返回值。这种泾渭分明的界限在某些场景下显得尤为僵硬,导致我们不得不编写重复或冗余的代码。
赋值表达式,官方代号 “The Walrus Operator”(海象运算符),即 :=,它的出现打破了这一常规。它允许我们在表达式内部直接进行变量赋值,并返回所赋的值。
看一个最直观的对比:
传统写法(Python 3.7 及以前):
# 我们需要先计算长度,再判断长度是否大于 0
text = get_data()
if len(text) > 0:
print(f"Received {len(text)} characters.")
这里 len(text) 被调用了两次。虽然在这个简单例子中性能影响微乎其微,但在更复杂的逻辑中,重复计算或重复调用函数是不优雅的。
使用赋值表达式(Python 3.8+):
# := 直接将计算结果赋值给 n,并返回 n 的值用于判断
if (n := len(get_data())) > 0:
print(f"Received {n} characters.")
通过 :=,我们成功将赋值操作嵌入到了表达式中。这不仅仅是代码行数的减少,更是逻辑流的改变——它解决了“我想在使用一个变量之前先计算它,但又不想把它放在上一行”的痛点。
2. 核心应用场景:让代码更简洁、更高效
赋值表达式并非为了炫技,它在特定的高频场景下能显著提升代码质量和可读性。
2.1 while 循环中的 read() 模式
处理文件读取或网络流时,经典的 while 循环写法通常是这样的:
# 传统写法
while True:
chunk = file.read(8192)
if not chunk:
break
process(chunk)
使用海象运算符,我们可以将 chunk 的赋值、判断和循环逻辑压缩到一行:
# 赋值表达式写法
while (chunk := file.read(8192)):
process(chunk)
这种写法极其接近 Unix C 语言中常见的 while ((n = read(fd, buf, sizeof buf)) > 0) 模式,对于习惯了底层编程的开发者来说,这既熟悉又高效。
2.2 列表推导式与 walrus 的威力
这是赋值表达式最能体现“复用计算结果”价值的地方。在 Python 3.8 之前,如果你想在列表推导式中过滤掉 None 或计算成本高昂的函数结果,通常需要写成这样:
# 传统写法:调用两次 expensive_func
data = [x for x in [expensive_func(i) for i in range(10)] if x is not None]
或者不得不放弃推导式,改用普通的 for 循环。
现在,我们可以这样做:
# 赋值表达式写法
data = [y for x in range(10) if (y := expensive_func(x)) is not None]
在这里,expensive_func(x) 只被调用了一次。我们将计算结果赋值给 y,然后在后续的过滤条件和最终输出中都使用了这个 y。这在处理大量数据或昂贵计算时,既优雅又实用。
2.3 if 分支中的复杂匹配
假设你正在处理正则匹配:
import re
data = "Python 3.8 released in 2019"
# 传统写法
match = re.search(r'Python (\\d\\.\\d)', data)
if match:
version = match.group(1)
print(f"Found version: {version}")
使用赋值表达式:
if (match := re.search(r'Python (\\d\\.\\d)', data)):
print(f"Found version: {match.group(1)}")
这种写法不仅减少了 match 变量的临时性占用,还让代码逻辑更加紧凑,明确表达了“如果匹配到了,就执行……”的意图。
3. 理解作用域:它不仅仅是“局部变量”
在使用赋值表达式时,最容易让人困惑的是变量的作用域问题。这是区分新手和熟练开发者的关键点。
3.1 列表推导式的新作用域
在 Python 3.8 中,列表推导式(以及集合、字典推导式)拥有自己的独立作用域。
x = "outer"
# 在推导式内部赋值 x
a = [x for x in range(3)]
# 外部的 x 不受影响
print(x) # 输出: "outer"
print(a) # 输出: [0, 1, 2]
在列表推导式内部使用 := 赋值的变量,其作用域被限制在推导式内部(类似于函数作用域),不会泄漏到外部。
3.2 循环与 if 块的作用域陷阱
然而,在普通的 if 语句或 while 循环中,:= 赋值的变量会直接泄漏到当前的作用域(即包含该语句的函数或全局作用域)。
看这个例子:
def demo():
data = [1, 2, 3, 4, 5]
if (n := len(data)) > 3:
print(f"List is too long: {n}")
# n 在这里依然存在!
print(n) # 输出: 5
更危险的陷阱:
y = 0
def bar():
# 这里并没有创建局部变量 y,而是修改了全局变量 y
if (y := 10) > 5:
pass
bar()
print(y) # 输出: 10 (全局变量被修改了!)
最佳实践建议: 为了避免这种副作用,建议在使用赋值表达式时:
4. 什么时候不应该使用赋值表达式?
虽然赋值表达式很强大,但滥用它会导致代码变得晦涩难懂。Python 之父 Guido van Rossum 最初甚至反对引入它,理由就是担心代码可读性下降。
以下情况请拒绝使用 :=:
表达式过于复杂时: 如果赋值部分和使用部分逻辑跨度很大,强行塞进一行是反人类的。
# 坏代码示例
if (match := re.search(r'…', text)) and (result := process(match.group(1))) and result.is_valid():
...
这种代码应该拆分成多行,或者干脆不要用赋值表达式。
为了赋值而赋值: 如果你只是想在循环中打印调试信息,不要用它。
# 坏代码示例
# 虽然能运行,但让人困惑
while (print(x := 1) or x < 10):
...
print 函数返回 None,这里的 or 逻辑很奇怪。
在 lambda 中使用: Python 3.8 不允许在 lambda 中使用赋值表达式(虽然在 Python 3.9+ 中放宽了限制,但依然不推荐)。如果逻辑复杂到需要在 lambda 里赋值,不如直接定义一个局部函数。
5. 总结与展望
赋值表达式 (:=) 是 Python 向表达式化编程迈进的重要一步。它主要解决了代码冗余和计算复用的问题。
核心要点回顾:
- 语法:name := expr,返回 name 的值。
- 优势:在 while 循环、列表推导式和 if 匹配中大幅减少代码行数和重复计算。
- 风险:注意变量作用域泄漏,尤其是在全局作用域或混合使用时。
- 原则:保持简单,不要为了使用而使用,优先考虑可读性。
掌握赋值表达式,意味着你的 Python 工具箱里多了一把锋利的瑞士军刀。在适当的地方使用它,能让你的代码更像 C 语言一样紧凑高效,同时保留 Python 的优雅。
你在日常开发中,遇到过哪些必须重复计算两次变量的场景?你觉得赋值表达式能解决你的痛点吗?欢迎在评论区分享你的代码片段!
网硕互联帮助中心






评论前必须登录!
注册