<< ..

Python解压可迭代序列赋值多个变量

发布时间:

阅读《Python Cookbook》体验到了不一样的Python,坚持一日一读一练。

问题

当我们得到一个多个元素的元组或列表,试图将里面的N个值解压同时赋值给N个对应的变量,如果解压对象和对应变量不对等,会出现一种问题ValueError: too many values to unpack:

>>> arg3 = (11, 22, 33)
>>> x, y = arg3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)
>>> x, y, z, k = arg3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  ValueError: too many values to unpack (expected 2)
>>> x, y, z = arg3

有时候我们确实不可能精确知道,待处理的序列中到底有多少个元素,但希望去除个别值,完成赋值操作,这个时候该怎么办?

解决方案

即刻召唤*号表达式完成需求,假如某项比赛评委打出分,去掉最高分和最低分:

>>> def get_mid_score(scores):
...     scores.sort()
...     lower, *middle, high = scores
...     return middle
...
>>> score_list = [79, 88, 89, 11, 10]
>>>
>>> get_mid_score(score_list)
[11, 79, 88]

靠着*表达式的思路,我们顺着摸索可以操作一个序列方法:

>>> record = ('diggzhang', 'dig@g.com', '139122','34211')
>>> name, email, *phone_nums = record
>>> phone_nums
['139122', '34211']

下面讨论一种迭代序列时候的高级用法,试想这样的应用场景,我们获取了一个不确定的序列,针对序列内的不同情况走不同的函数传值去处理,如下,算法精简直白:

>>> records = [
...     ('foo', 1, 2),
...     ('bar', 'hello'),
...     ('foo', 3, 4)
... ]
>>> def do_foo(x, y):
...     print('fooo', 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)
...
fooo 1 2
bar hello
fooo 3 4
>>>

*表达式还可以同时应用于字符串分割:

>>> line = '_coremediaiod:*:236:236:Core Media IO Daemon:/var/empty:/usr/bin/false'
>>> user, *fields, homedir, sh = line.split(':')
>>> user
'_coremediaiod'
>>> homedir
'/var/empty'
>>> sh
'/usr/bin/false'
>>>