1.2 解压可迭代对象赋值给多个变量
解决方案
Python 的星号表达式可以用来解决这个问题。比如,你在学习一门课程,在学期末的时候, 你想统计下家庭作业的平均成绩,但是排除掉第一个和最后一个分数。如果只有四个分数,你可能就直接去简单的手动赋值, 但如果有 24 个呢?这时候星号表达式就派上用场了:
1 2 3 | def drop_first_last(grades): first, *middle, last = grades return sum(middle) / len(grades) - 2 |
另外一种情况,假设你现在有一些用户的记录列表,每条记录包含一个名字、邮件,接着就是不确定数量的电话号码。 你可以像下面这样分解这些记录:
1 2 3 4 5 6 7 8 9 | >>> record = ( 'Dave' , 'dave@example.com' , '773-555-1212' , '847-555-1212' ) >>> name, email, *phone_numbers = record >>> name 'Dave' >>> email 'dave@example.com' >>> phone_numbers [ '773-555-1212' , '847-555-1212' ] >>> |
值得注意的是上面解压出的 phone_numbers
变量永远都是列表类型,不管解压的电话号码数量是多少(包括 0 个)。 所以,任何使用到 phone_numbers
变量的代码就不需要做多余的类型检查去确认它是否是列表类型了。
星号表达式也能用在列表的开始部分。比如,你有一个公司前 8 个月销售数据的序列, 但是你想看下最近一个月数据和前面 7 个月的平均值的对比。你可以这样做:
1 2 3 | *trailing_qtrs, current_qtr = sales_record trailing_avg = sum(trailing_qtrs) / len(trailing_qtrs) return avg_comparison(trailing_avg, current_qtr) |
下面是在 Python 解释器中执行的结果:
1 2 3 4 5 | >>> *trailing, current = [10, 8, 7, 1, 9, 5, 10, 3] >>> trailing [10, 8, 7, 1, 9, 5, 10] >>> current 3 |
讨论
扩展的迭代解压语法是专门为解压不确定个数或任意个数元素的可迭代对象而设计的。 通常,这些可迭代对象的元素结构有确定的规则(比如第 1 个元素后面都是电话号码), 星号表达式让开发人员可以很容易的利用这些规则来解压出元素来。 而不是通过一些比较复杂的手段去获取这些关联的元素值。
值得注意的是,星号表达式在迭代元素为可变长元组的序列时是很有用的。 比如,下面是一个带有标签的元组序列:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | records = [ ( 'foo' , 1, 2), ( 'bar' , 'hello' ), ( 'foo' , 3, 4), ] def do_foo(x, y): print( 'foo' , x, y) def do_bar(s): print( 'bar' , s) for tag, *args in records: if tag == 'foo' : do_foo(*args) elif tag == 'bar' : do_bar(*args) foo 1 2 bar hello foo 3 4 |
星号解压语法在字符串操作的时候也会很有用,比如字符串的分割。
代码示例:
1 2 3 4 5 6 7 8 9 | >>> line = 'nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false' >>> uname, *fields, homedir, sh = line.split( ':' ) >>> uname 'nobody' >>> homedir '/var/empty' >>> sh '/usr/bin/false' >>> |
有时候,你想解压一些元素后丢弃它们,你不能简单就使用 *
, 但是你可以使用一个普通的废弃名称,比如 _
或者 ign
(ignore)。
代码示例:
1 2 3 4 5 6 7 | >>> record = ( 'ACME' , 50, 123.45, (12, 18, 2012)) >>> name, *_, (*_, year) = record >>> name 'ACME' >>> year 2012 >>> |
在很多函数式语言中,星号解压语法跟列表处理有许多相似之处。比如,如果你有一个列表, 你可以很容易的将它分割成前后两部分:
1 2 3 4 5 6 7 | >>> items = [1, 10, 7, 4, 5, 9] >>> head, *tail = items >>> head 1 >>> tail [10, 7, 4, 5, 9] >>> |
如果你够聪明的话,还能用这种分割语法去巧妙的实现递归算法。比如:
1 2 3 | def my_sum(items): head, *tail = items return head + my_sum(tail) if tail else head |
然后,由于语言层面的限制,递归并不是 Python 擅长的。 因此,最后那个递归演示仅仅是个好奇的探索罢了,对这个不要太认真了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律