【Python3】从任意长度的可迭代对象中分解元素

*表达式 解决too many values to unpack的异常

假设有24个成绩,去头掐尾
python 复制代码
# 定义一个函数,用于去掉列表中的第一个和最后一个元素,并返回剩余元素的平均值
def drop_first_last(grades):
    # 使用解包的方式,将列表中的第一个元素赋值给变量first,
    #剩余元素赋值给变量middle,
    # 最后一个元素赋值给变量last
    first, *middle, last = grades
    # 返回剩余元素的平均值
    return avg(middle)
假设有一些用户数据,附带任意数量的电话号码
ini 复制代码
# 定义一个元组record,包含四个元素
record = ('Dave', 'dave@example.com', '773-555-1212', '847-555-1212')
# 使用*phone_numbers将元组record中的前两个元素赋值给name和email,剩余的元素赋值给phone_numbers
name, email, *phone_numbers = record
# 打印phone_numbers
print(phone_numbers)
假设要让最后的一个季度的销售额和前面几个季度的均值作对比
ini 复制代码
# 计算过去四季度销售额的平均值
*trailing_qtr = sales_record
# 计算过去四季度销售额的总和
trailing_avg = sum(trailing_qtr) / len(trailing_qtr)
# 返回与当前季度销售额的比较结果
return avg_comparison(trailing_avg, current_qtr)

星号在变量名前的意思是,这个变量将接收解包后的所有剩余元素。换句话说,如果 sales_record 是一个包含四个元素的列表,那么 trailing_qtr 将会是一个包含前三个元素的列表,而第四个元素将被赋值给 trailing_qtr

例如:

ini 复制代码
sales_record = [10, 20, 30, 40]
*trailing_qtr, last_qtr = sales_record

在这个例子中,trailing_qtr 将会是 [10, 20, 30],而 last_qtr 将会是 40

需要注意的是,这种解包语法要求左侧的变量数量不能超过可迭代对象的元素数量。如果 sales_record 只包含三个元素,那么上述代码将会引发 ValueError,因为左侧有四个变量(包括 *trailing_qtr 中的三个元素和 last_qtr)。

此外,*trailing_qtr 这种用法在赋值语句的左侧是Python 3.0引入的。在Python 2.x中,这种语法是不支持的。

假设有一个带标记的元组:
python 复制代码
record = [('foo', 1, 2),
          ('bar', 'hello'), 
           ('foo', 3, 4)]
# 定义一个函数,参数为x和y,打印出'foo'和x、y的值
def do_foo(x, y):
    print('foo', x, y)
# 定义一个函数,参数为s,打印出'bar'和s的值
def do_bar(s):
    print('bar', s)
# 遍历record列表,tag为record中的第一个元素,args为record中的剩余元素
for tag, *args in record:
    # 如果tag为'foo',则调用do_foo函数,并传入args中的参数
    if tag == 'foo':
        do_foo(*args)
    # 如果tag为'bar',则调用do_bar函数,并传入args中的参数
    elif tag == 'bar':
        do_bar(*args)
split拆分
bash 复制代码
# 定义一个字符串变量line,包含一个用户信息
line = 'nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false'
# 使用split()方法将字符串按照冒号分割,得到一个列表
uname, *fields, homedir, sh = line.split(':')
print(uname)
print(fields)
print(homedir)
print(sh)
拆分后丢弃
scss 复制代码
record = ('ACME', 50, 123.45, (12, 18, 2023))
name, *_, (*_, year) = record
print(name)
print(year)
print(record)
头尾分离
bash 复制代码
# 定义一个列表items,包含6个元素
items = [1, 10, 7, 4, 5, 9]
# 使用解包操作符*,将列表items的第一个元素赋值给head,剩余的元素赋值给tail
head, *tail = items
# 打印head的值
print(head)
# 打印tail的值
print(tail)
# 使用解包操作符*,将tail中的元素依次打印出来
print(*tail)
应用递归
bash 复制代码
# 定义一个函数sum,参数为items
def sum(items):
    # 将items列表拆分为head和tail两部分,head为列表的第一个元素,tail为剩余的元素
    head, *tail = items
    # 如果tail不为空,则递归调用sum函数,将tail作为参数传入,并将head和递归调用的结果相加
    # 如果tail为空,则返回head
    return head + sum(tail) if tail else head
  1. 这行代码是递归的核心部分:

    • 如果 tail 不为空(即列表中还有元素),则递归调用 sum 函数,将 tail 作为参数传入,并将 head 和递归调用的结果相加。
    • 如果 tail 为空(即列表中只有一个元素),则直接返回 head

实现原理

这个函数通过递归的方式不断地将列表拆分为第一个元素和剩余的元素,然后将第一个元素与剩余元素的总和相加,直到列表中只剩下一个元素为止。

用途

这个函数可以用来计算一个列表中所有元素的总和。例如,sum([1, 2, 3, 4]) 将返回 10

注意事项

  1. 输入类型 :这个函数假设输入的 items 是一个列表。如果传入的不是列表,代码会抛出错误。
  2. 空列表 :如果传入一个空列表,这个函数会抛出错误,因为 head 会尝试访问列表的第一个元素,但列表是空的。
  3. 性能:对于非常大的列表,这种递归方式可能会导致性能问题,因为递归调用会增加调用栈的深度。

改进

为了处理空列表的情况,可以在函数开始时添加一个检查:

bash 复制代码
Python
 复制 插入 新文件
def sum(items):
    if not items:
        return 0
    head, *tail = items
    return head + sum(tail) if tail else head

这样,如果传入的是空列表,函数将返回 0

相关推荐
用户2986985301421 分钟前
.NET 文档自动化:Spire.Doc 设置奇偶页页眉/页脚的最佳实践
后端·c#·.net
序安InToo1 小时前
第6课|注释与代码风格
后端·操作系统·嵌入式
xyy1231 小时前
C#: Newtonsoft.Json 到 System.Text.Json 迁移避坑指南
后端
洋洋技术笔记1 小时前
Spring Boot Web MVC配置详解
spring boot·后端
JxWang051 小时前
VS Code 配置 Markdown 环境
后端
navms1 小时前
搞懂线程池,先把 Worker 机制啃明白
后端
JxWang051 小时前
离线数仓的优化及重构
后端
Nyarlathotep01131 小时前
gin01:初探gin的启动
后端·go
JxWang051 小时前
安卓手机配置通用多屏协同及自动化脚本
后端
JxWang051 小时前
Windows Terminal 配置 oh-my-posh
后端