1 带星号的 unpacking 操作

拆解单层

  1. car_ages = [0, 9, 4, 8, 7, 20, 19, 1, 6, 15]
  2. car_ages_descending = sorted(car_ages, reverse=True)
  3. oldest, second_oldest, *others = car_ages_descending
  4. print(oldest, second_oldest, others)
  5. oldest, *others, youngest = car_ages_descending
  6. print(oldest, youngest, others)
  7. *others, second_youngest, youngest = car_ages_descending
  8. print(youngest, second_youngest, others)

image.png

拆解多层

  1. car_inventory = {
  2. 'Downtown': ('Silver Shadow', 'Pinto', 'DMC'),
  3. 'Airport': ('Skyline', 'Viper', 'Gremlin', 'Nova'),
  4. }
  5. ((loc1, (best1, *rest1)),
  6. (loc2, (best2, *rest2))) = car_inventory.items()
  7. print(f'Best at {loc1} is {best1}, {len(rest1)} others')
  8. print(f'Best at {loc2} is {best2}, {len(rest2)} others')

image.png

2 用在迭代器上

  • unpacking 操作也可以用在迭代器上,但是这样写与把数据拆分到多个变量里面的那种基本写法相比,并没有太大优势。
  • 例如,我可以先构造长度为 2 的取值范围(range),并把它封装在 it 这个迭代器里,然后将其中的值拆分到 first 与 second 这两个变量里。
  • 但这样写还不如直接使用形式相符的静态列表(例如 [1, 2]),那样更简单。

    1. it = iter(range(1, 3))
    2. print(it)
    3. first, second = it
    4. print(f'{first} and {second}')
  • 对迭代器做 unpacking 操作的好处,主要体现在带星号的用法上面,它使迭代器的拆解值更清晰。例如,这里有个生成器,每次可以从含有整个一周的汽车订单的 CSV 文件中取出一行数据。

  • 我们可以用下标和切片来处理这个生成器所给出的结果,但这样写需要很多行代码, 而且看着比较混乱。 ```python def generate_csv(): yield (‘Date’, ‘Make’ , ‘Model’, ‘Year’, ‘Price’) for i in range(100):
    1. yield ('2019-03-25', 'Honda', 'Fit' , '2010', '$3400')
    2. yield ('2019-03-26', 'Ford', 'F150' , '2008', '$2400')

all_csv_rows = list(generate_csv()) header = all_csv_rows[0] rows = all_csv_rows[1:] print(‘CSV Header:’, header) print(‘Row count: ‘, len(rows))

  1. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/22011425/1649089913050-fc7995c9-6c95-41fb-b0fd-7c7c8e1af405.png#clientId=u06c19f44-3562-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=49&id=ube6a1802&margin=%5Bobject%20Object%5D&name=image.png&originHeight=61&originWidth=401&originalType=binary&ratio=1&rotation=0&showTitle=false&size=6026&status=done&style=none&taskId=udeef61b5-236e-4998-9f7d-90b4d0fd446&title=&width=320.8)
  2. - 利用带星号的 unpacking 操作,我们可以把第一行(表头)单独放在 header 变量里,
  3. - 同时把迭代器所给出的其余内容合起来表示成 rows 变量。
  4. - 这样写就清楚多了。
  5. ```python
  6. def generate_csv():
  7. yield ('Date', 'Make' , 'Model', 'Year', 'Price')
  8. for i in range(100):
  9. yield ('2019-03-25', 'Honda', 'Fit' , '2010', '$3400')
  10. yield ('2019-03-26', 'Ford', 'F150' , '2008', '$2400')
  11. it = generate_csv()
  12. header, *rows = it
  13. print('CSV Header:', header)
  14. print('Row count: ', len(rows))

image.png

  • 带星号的这部分总是会形成一份列表,所以要注意,这有可能耗尽计算机的全部内存并导致程序崩溃。
  • 首先必须确定系统有足够的内存可以存储拆分出来的结果数据,然后才可以对迭代器使用带星号的 unpacking 操作(还有另一种做法,参见第 31 条)。

    3 总结

  • 拆分数据结构并把其中的数据赋给变量时,可以用带星号的表达式,将结构中无法与普通变量相匹配的内容捕获到一份列表里。

  • 这种带星号的表达式可以出现在赋值符号左侧的任意位置,它总是会形成一份含有零个或多个值的列表。
  • 在把列表拆解成互相不重叠的多个部分时,这种带星号的 unpacking 方式比较清晰,而通过下标与切片来实现的方式则很容易出错。