Python中的任何序列(可迭代的对象)都可以通过赋值操作进行拆分,包括但不限于元组、列表、字符串、文件、迭代器、生成器等。

元组拆分

元组拆分是最为常见的一种拆分,示例如下:

p = (4, 5)
x, y = p
print(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 = s
print(a) # H

拆分时丢弃值

如果在拆分时想丢弃某些特定的值,可以用一个用不到的变量名来作为丢弃值的名称(常选'_'做为变量名),如下所示:

s = 'Hello'
a, b, _, d, _ = s
print(a) # H

嵌套序列拆分

Python也提供简洁的对嵌套序列进行拆分的语法。如下所示我们对一个比较复杂的异质列表进行拆分:

data = ['zhy', 50, 123.0, (2000, 12, 21)]
name, shares, price, (year, month, day) = data
print(year) # 2000

如果你想完整地得到(2000, 12, 21)这个表示时间戳的元组,那么你就得这样写:

data = ['zhy', 50, 123.0, (2000, 12, 21)]
name, shares, price, date = data
print(date) # (2000, 12, 21)

从任意长度的可迭代对象中拆分

之前我们说过,如果我们想从可迭代对象中分解出\(N\)个元素,但如果这个可迭代对象长度超过\(N\),则会抛出异常"too many values to unpack"。针对这个问题的解决方案是采用"*"表达式。

比如我们给定学生的分数,想去掉一个最高分和一个最低分,然后对剩下的学生求平均分,我们可以这样写:

def avg(data: list):
return sum(data)/len(data)
# 去掉最高分,最低分然后做均分统计
def drop_first_last(grades):
first, *middle, last = grades
return 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 = record
print(phone_numbers) # ['773-556234', '774-223333']

事实上,如果电话号码为空也是合法的,此时phone_numbers为空列表。

record = ['zhy', 'zhy1056692290@qq.com']
name, email, *phone_numbers = record
print(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) = record
print(year) # 2012

最后再介绍*表达式用于递归函数的一种黑魔法,比如与递归求和结合可以这样写:

items = [1, 10, 7, 4, 5, 9]
def sum(items):
head, *tail = items
return head + sum(tail) if tail else head
print(sum(items)) # 36

不过,Python由于自身递归栈的限制,并不擅长递归。我们最后一个递归的例子可以做为一种学术上的尝试,但不建议在实践中使用它。

参考文献

  • [1] Martelli A, Ravenscroft A, Ascher D. Python cookbook[M]. " O'Reilly Media, Inc.", 2005.

Python技法1:变长和定长序列拆分的更多相关文章

  1. loadrunner socket协议问题归纳(4)---buffer接收变长和定长的数据

    测试场景:聊天系统 用户登录后,要先向服务器发送用户名,然后可以发送聊天信息,同时也可以接受聊天信息. 如果接受的字符为定长时,可以设定接受长度.recv buf2 66 #include " ...

  2. 报文格式:xml 、定长报文、变长报文

    目前接触到的报文格式有三种:xml .定长报文.变长报文 . 此处只做简单介绍,日后应该会深入学习到三者之间如何解析,再继续更新.——2016.9.23 XML XML 被设计用来传输和存储数据. H ...

  3. 快学Scala 第三课 (定长数组,变长数组, 数组循环, 数组转换, 数组常用操作)

    定长数组定义: val ar = new Array[Int](10) val arr = Array("aa", "bb") 定长数组赋值: arr(0) = ...

  4. Python 数据处理----对定长数据的处理

    场景: 有时候我们对大量数据进行处理,对性能要求很高,而且数据都是定长的,比如对移动信息登记表进行处理:名字 身份证信息 手机号码 这些都是定长的,今天小花来教大家如何对此类数据进行处理. 步骤一: ...

  5. 定长内存池之BOOST::pool

    内存池可有效降低动态申请内存的次数,减少与内核态的交互,提升系统性能,减少内存碎片,增加内存空间使用率,避免内存泄漏的可能性,这么多的优点,没有理由不在系统中使用该技术. 内存池分类: 1.      ...

  6. django使用pyecharts(6)----django加入echarts_增量更新_定长_坐标轴定长

    六.Django 前后端分离_定时增量更新图表(坐标轴定长) 1.安装 djangorestframework linux pip3 install djangorestframework windo ...

  7. django使用pyecharts(5)----django加入echarts_增量更新_定长

    五.Django 前后端分离_定时增量更新图表定长数据 1.安装 djangorestframework linux pip3 install djangorestframework windows ...

  8. Netty(四)分隔符与定长解码器的使用

    TCP以流的形式进行数据传输,上层的应用协议为了对消息进行划分,往往采用如下的4种方式. (1)消息长度固定,累计读到长度总和为定长len的报文后,就认为读取到了一个完整的消息:然后重新开始读取下一个 ...

  9. javascript实现数据结构:串--定长顺序存储表示以及kmp算法实现

    串(string)(或字符串)是由零个或多个字符组成的有限序列.串中字符的数目称为串的长度.零个字符的串称为空串(null string),它的长度为零. 串中任意个连续的字符组成的子序列称为该串的子 ...

随机推荐

  1. Java(1)开发环境配置及第一个程序Hello World

    作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15201468.html 博客主页:https://www.cnblogs.com/testero ...

  2. 理解ASP.NET Core - 路由(Routing)

    注:本文隶属于<理解ASP.NET Core>系列文章,请查看置顶博客或点击此处查看全文目录 Routing Routing(路由):更准确的应该叫做Endpoint Routing,负责 ...

  3. logstash的mutate过滤器的使用

    logstash的mutate过滤器的使用 一.背景 二.需求 三.实现步骤 1.安装 `csv codec` 插件 2.准备需要读取的文件数据 3.编写 pipeline ,读取和输出数据 4.mu ...

  4. 手写vue-router & 什么是Vue插件

    博文分享 这篇文章你可以学习到: 实现一个自己的vue-router 了解什么是Vue的插件 学习b站大佬后做的笔记整理和源码实现 1.1.3一步一步带你弄懂vue-router核心原理及实现哔哩哔哩 ...

  5. 助你上手Vue3全家桶之VueX4教程

    目录 1,前言 2,State 2.1,直接使用 2.2,结合computed 3,Getter 3.1,直接使用 3.2,结合computed 4,Mutation 4.1,直接使用 4.2,结合c ...

  6. 转:VCS仿真vivado IP的方法

    vivado中的仿真库和模型与ISE中的是不一样的,因此在vivado中使用VCS进行仿真的方法也与ISE中不一样. VCS可以通过两种方法对XILINX的器件进行功能仿真和门级仿真,这两种方法是 P ...

  7. python教程-(四)当索引行不通时(python字典)

    一.创建和使用字典 1.函数dict #字典表示方式如下 >>> phonebook = {'tom':'18616271234',"Jim":"186 ...

  8. 【mysql1】如何删除MySQL内存|不再跟新系列

    完全卸载mysql的具体步骤: 包括停止服务  +  卸载相关程序  +  删除注册表等等 步骤一:  windows键+R-->Control-->程序和功能:所有MySQL程序点击右键 ...

  9. Swift进阶-内存管理

    本文的主要目的是探索 RefCount 的内存结构及强/弱引用计数管理 Swift 中也是采用 ARC 编译器自动内存管理机制. Swift 对象的内存结构是 HeapObject, 有两个属性 Me ...

  10. Java操作MongoDB之mongodb-driver(一)

    1. mongodb-driver是mongo官方推出的java连接mongoDB的驱动包,相当于JDBC驱动. (1)通过maven仓库导入:https://mvnrepository.com/ar ...