欢迎大家扫码关注我的微信公众号:
从任意长度的可迭代对象中分解元素
- 一、问题
- 二、解决方案
- 2.1 * 表达式在首位
- 2.2 * 表达式在中间
- 2.3 * 表达式在末位
- 三、讨论
一、问题
需要从某个可迭代对象中分解出 N 个元素, 但是这个可迭代对象的长度可能超过 N, 这会导致出现 “分解值过多(too many values to unpack)” 的异常。
二、解决方案
Python 的 “* 表达式” 可以用来解决这个问题。 且它可以出现在任意位置。
2.1 * 表达式在首位
需求: 有一个未知长度的列表, 其内均为 int 型元素。 现需要求出最后一个元素之前的所有元素的平均值与最后一个元素的差值。
解决:
>>> *a, c = [1, 2, 3]
>>> b = sum(a) / len(a)
>>> b - c
-1.5
2.2 * 表达式在中间
需求:有一个未知长度的列表, 其内均为 int 型元素。 现需求出除第一个和最后一个元素之外其余所有元素的平均值。
解决:
>>> a, *b, c = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> sum(b) / len(b)
5.0
2.3 * 表达式在末位
需求: 有一个未知长度的列表, 其内第一个元素是学生姓名, 第二个元素是性别, 从第三个开始是他的考试成绩(不定长)。 现需要将该学生的所有成绩取出来。
解决:
>>> name, sex, *scores = ['Cybeyond', 'Male', 99, 100, 89, 92, 97]
>>> name
'Cybeyond'
>>> sex
'Male'
>>> scores
[99, 100, 89, 92, 97]
三、讨论
对于分解未知长度的可迭代对象, 利用 * 表达式使得开发者可以轻松地得到所关心的元素, 而不必在可迭代对象中做复杂花哨的操作。
*表达式在迭代一个变长的元组序列时尤其有用:
>>> lst = [('foo', 1, 2), ('bar', 'aa'), ('foo', 3, 4), ('bar', 'bb')]
>>>
>>> def do_foo(x, y):
... print('foo', x, y)
...
>>>
>>> def do_bar(s):
... print('bar', s)
...
>>>
>>> for tag, *args in lst:
... if tag == 'foo':
... do_foo(*args)
... elif tag == 'bar':
... do_bar(*args)
...
foo 1 2
bar aa
foo 3 4
bar bb
当和某些特定的字符串处理操作相结合, 比如拆分操作时:
>>> url = 'https://127.0.0.1:8080/rest/get_data/?id=4&tag=cybeyond&name=xuan'
>>> _, tag_requirement, name_requirement = url.split('&')
>>> tag_requirement
'tag=cybeyond'
>>> name_requirement
'name=xuan'
可以使用几个常用来表示丢弃值的变量名来承接想要丢弃的值, 如 _ 或 ign(ignore):
>>> name, _, *scores = ['Cybeyond', 'Male', 99, 100, 89, 92, 97]
>>> name
'Cybeyond'
>>> scores
[99, 100, 89, 92, 97]
【注意】本篇博客中所写的全部内容只能在 Python 3 版本中成功运行, 在 Python 2 版本中将会报 SyntaxError: invalid syntax 异常!!!