Python中的任何序列(可迭代的对象)都可以通过赋值操作进行拆分,包括但不限于元组、列表、字符串、文件、迭代器、生成器等。
元组拆分
元组拆分是最为常见的一种拆分,示例如下:
p = (4, 5)x, y = pprint(x, y) # 4 5
如果写成
x, y, z = p
那么就会抛出ValueError异常:“not enough values to unpack (expected 3, got 2)”
如果写成
p = (4, 5, 6)x, y = p
那么就会抛出ValueError异常:“too many values to unpack (expected 2)”
字符串拆分
字符串的拆分示意如下:
s = \'Hello\'a, b, c, d, e = sprint(a) # H
拆分时丢弃值
如果在拆分时想丢弃某些特定的值,可以用一个用不到的变量名来作为丢弃值的名称(常选\’_\’做为变量名),如下所示:
s = \'Hello\'a, b, _, d, _ = sprint(a) # H
嵌套序列拆分
Python也提供简洁的对嵌套序列进行拆分的语法。如下所示我们对一个比较复杂的异质列表进行拆分:
data = [\'zhy\', 50, 123.0, (2000, 12, 21)]name, shares, price, (year, month, day) = dataprint(year) # 2000
如果你想完整地得到(2000, 12, 21)这个表示时间戳的元组,那么你就得这样写:
data = [\'zhy\', 50, 123.0, (2000, 12, 21)]name, shares, price, date = dataprint(date) # (2000, 12, 21)
从任意长度的可迭代对象中拆分
之前我们说过,如果我们想从可迭代对象中分解出\\(N\\)个元素,但如果这个可迭代对象长度超过\\(N\\),则会抛出异常\”too many vad8alues to unpack\”。针对这个问题的解决方案是采用\”*\”表达式。
比如我们给定学生的分数,想去掉一个最高分和一个最低分,然后对剩下的学生求平均分,我们可以这样写:
def avg(data: list):return sum(data)/len(data)# 去掉最高分,最低分然后做均分统计def drop_first_last(grades):first, *middle, last = gradesreturn avg(middle)print(drop_first_last([1,2,3,4])) # 2.5
还有一种情况是有一些用户记录,记录由姓名+电子邮件+任意数量的电话号码组成,则我们可以这样分解用户记录:
record = [\'zhy\', \'zhy1056692290@qq.com\', \'773-556234\', \'774-223333\']name, email, *phone_numbers = recordprint(phone_numbers) # [\'773-556234\', \'774-223333\']
事实上,如果电话号码为空也是合法的,此时phone_numbers为空列表。
record = [\'zhy\', \'zhy1056692290@qq.com\']name, email, *phone_numbers = recordprint(phone_numbers) # []
还有一种使用情况则更为巧妙。如果我们需要遍历变长元组组成的列表,这些元组长度不一。那么此时*表达式可大大简化我们的代码。
records = [(\'foo\', 1, 2), (\'bar\', \'hello\'), (\'foo\', 3, 4)]for tag, *args in records:if tag == \'bar\':print(args)# [\'hello\']
在对一些复杂的字符串进行拆分时,*表达式也显得特别有用。
line = \"nobody:*:-2:-2:-2:Unprivileged User:/var/empty:/usr/bin/false\"uname, *fields, home_dir, sh = line.split(\':\')print(home_dir) # /var/empty
*表达式也可以和我们前面说的嵌套拆分和变量丢弃一起结合使用。
record = [\'ACME\', 50, 123.45, (128, 18, 2012)]name, *_, (*_, year) = recordprint(year) # 2012
最后再介绍*表达式用于递归函数的一种黑魔法,比如与递归求和结合可以这样写:
items = [1, 10, 7, 4, 5, 9]def sum(items):head, *tail = itemsreturn head + sum(tail) if tail else headprint(sum(items)) # 36
不过,Python由于自身递归栈的限制,并不擅长递归。我们最后一个递归的例子可以做为一种学术上的尝试,但不建议在实践中使用它。
参考文献
- [1] Martelli A, Ravenscroft A, Ascher D. Python cookbook[M]. \” O\’Reilly Media, Inc.\”, 2005.