鱼C论坛

 找回密码
 立即注册
查看: 1851|回复: 14

[技术交流] 【Cookbook】解压可迭代对象赋值给多个变量

[复制链接]
发表于 2020-3-8 18:38:10 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回顾:【Cookbook】解压序列赋值给多个变量问题
https://fishc.com.cn/thread-159566-1-1.html


                               
登录/注册后可看大图


问题
如果一个可迭代对象的元素个数超过变量个数时,会抛出一个ValueError 。 那么怎样才能从这个可迭代对象中解压出 N 个元素出来?

                               
登录/注册后可看大图



解决方案
Python 的星号表达式可以用来解决这个问题。比如,你在学习一门课程,在学期末的时候, 你想统计下家庭作业的平均成绩,但是排除掉第一个和最后一个分数。如果只有四个分数,你可能就直接去简单的手动赋值, 但如果有 24 个呢?这时候星号表达式就派上用场了
def drop_first_last(grades):
    first, *middle, last = grades
    return avg(middle)
另外一种情况,假设你现在有一些用户的记录列表,每条记录包含一个名字、邮件,接着就是不确定数量的电话号码。 你可以像下面这样分解这些记录:
>>> 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 个月的平均值的对比。你可以这样做:
*trailing_qtrs, current_qtr = sales_record
trailing_avg = sum(trailing_qtrs) / len(trailing_qtrs)
return avg_comparison(trailing_avg, current_qtr)
下面是在 Python 解释器中执行的结果:
>>> *trailing, current = [10, 8, 7, 1, 9, 5, 10, 3]
>>> trailing
[10, 8, 7, 1, 9, 5, 10]
>>> current
3

                               
登录/注册后可看大图


讨论
扩展的迭代解压语法是专门为解压不确定个数或任意个数元素的可迭代对象而设计的。 通常,这些可迭代对象的元素结构有确定的规则(比如第 1 个元素后面都是电话号码), 星号表达式让开发人员可以很容易的利用这些规则来解压出元素来。 而不是通过一些比较复杂的手段去获取这些关联的元素值。

值得注意的是,星号表达式在迭代元素为可变长元组的序列时是很有用的。 比如,下面是一个带有标签的元组序列:
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)
星号解压语法在字符串操作的时候也会很有用,比如字符串的分割。

  • 代码示例:
>>> 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)。

  • 代码示例:
>>> record = ('ACME', 50, 123.45, (12, 18, 2012))
>>> name, *_, (*_, year) = record
>>> name
'ACME'
>>> year
2012
>>>
在很多函数式语言中,星号解压语法跟列表处理有许多相似之处。比如,如果你有一个列表, 你可以很容易的将它分割成前后两部分:
>>> items = [1, 10, 7, 4, 5, 9]
>>> head, *tail = items
>>> head
1
>>> tail
[10, 7, 4, 5, 9]
>>>
如果你够聪明的话,还能用这种分割语法去巧妙的实现递归算法。比如:
>>> def sum(items):
...     head, *tail = items
...     return head + sum(tail) if tail else head
...
>>> sum(items)
36
>>>
然后,由于语言层面的限制,递归并不是 Python 擅长的因此,最后那个递归演示仅仅是个好奇的探索罢了,对这个不要太认真了。

摘自《Python Cookbook》第三版
本翻译项目源地址:<a href="https://github.com/yidao620c/python3-cookbook" target="_blank">https://github.com/yidao620c/python3-cookbook</a>
Copyright (c) 2014-2018 Xiong Neng and other contributors
遵循Apache License 2.0 协议
索引贴

暂无待更新~

由于原项目在线阅读不方便,因此转载给各位鱼油(我才不会说是水经验!)
Cookbook系列帖子正在不断完善哦,希望能对已经初步了解python的你有所帮助~
获取更新欢迎关注淘帖https://fishc.com.cn/forum.php?mod=collection&action=view&ctid=1664


喜欢记得评分哦!


评分

参与人数 1荣誉 +1 鱼币 +1 收起 理由
乘号 + 1 + 1 鱼C有你更精彩^_^

查看全部评分

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-3-9 08:59:13 | 显示全部楼层

回帖奖励 +2 鱼币

VIP就是牛
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-9 09:27:14 | 显示全部楼层

回帖奖励 +2 鱼币

学习了,难得的精华
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-9 10:29:57 | 显示全部楼层

回帖奖励 +2 鱼币

营养丰富 !!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-9 10:30:07 | 显示全部楼层

回帖奖励 +2 鱼币

虽然看不懂还是学习一下
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-10 14:21:13 | 显示全部楼层

回帖奖励 +2 鱼币

0
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-3-10 14:32:22 | 显示全部楼层

回帖奖励 +2 鱼币

感谢分享
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-10 14:35:13 | 显示全部楼层
感谢分享
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-12 08:17:57 | 显示全部楼层

回帖奖励 +2 鱼币

感谢分享
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-12 13:57:30 | 显示全部楼层
.
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-3-13 13:02:32 | 显示全部楼层

回帖奖励 +2 鱼币

感谢分享
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-13 14:42:02 | 显示全部楼层

回帖奖励 +2 鱼币

感谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-3-13 18:22:46 | 显示全部楼层

回帖奖励 +2 鱼币

def drop_first_last(grades):
    first, *middle, last = grades
    return avg(middle)
为什么不写成
def drop_first_last(grades):
  return avg(grades[1:-1])
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-3-13 19:39:53 | 显示全部楼层

因为这里要对可迭代对象讨论星号表达式啊。可迭代对象不都支持索引,字符串,元组,列表这些有序可迭代对象是支持index的,而集合和字典是不支持index的.
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-14 12:19:13 | 显示全部楼层
dlnb526 发表于 2020-3-13 19:39
因为这里要对可迭代对象讨论星号表达式啊。可迭代对象不都支持索引,字符串,元组,列表这些有 ...


然而对于集合和字典这种对象,你并不知道他会给你赋一个什么样的值,所以好像并没有什么用
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-17 00:08

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表