
3.2 使用元组
在Python程序中,可以将元组看作是一种特殊的列表。唯一与列表不同的是,元组内的数据元素不能发生改变。不但不能改变其中的数据项,而且也不能添加和删除数据项。当开发者需要创建一组不可改变的数据时,通常会把这些数据放到一个元组中。

↑扫码看视频(本节视频课程时间:7分59秒)
3.2.1 实战演练——创建并访问元组
在Python程序中,创建元组的基本形式是以小括号“()”将数据元素括起来,各个元素之间用逗号“,”隔开。例如,下面都是合法的元组。

Python语言允许创建空元组,例如,下面的代码创建了一个空元组。

在Python程序中,当在元组中只包含一个元素时,需要在元素后面添加逗号“,”。例如下面的演示代码:

在Python程序中,元组与字符串和列表类似,下标索引也是从0开始的,并且也可以进行截取和组合等操作。在下面的实例文件zu.py,演示了创建并访问两个元组的过程。

在上述代码中定义了两个元组“tup1”和“tup2”,在第4行代码中读取了元组“tup1”中索引为0的元素的值,然后在第6行代码中读取了元组“tup2”中索引从1到4的元素的值。执行效果如图3-10所示。

图3-10 执行效果
3.2.2 实战演练——连接组合元组
在Python程序中,元组一旦创立后就不可被修改。但是在现实程序应用中,开发者可以对元组进行连接组合。在下面的实例文件lian.py中,演示了连接组合两个元组并输出新元组中元素值的过程。

在上述代码中定义了两个元组“tup1”和“tup2”,然后将这两个元组进行连接组合,将组合后的值赋给新元组“tup3”。执行后输出新元组“tup3”中的元素值,执行效果如图3-11所示。

图3-11 执行效果
3.2.3 实战演练——删除元组
在Python程序中,虽然不允许删除一个元组中的元素值,但是可以使用del语句来删除整个元组。在下面的实例文件shan.py中,演示了使用del语句来删除整个元组的过程。

在上述代码中定义了一个元组“tup”,然后使用del语句来删除整个元组的过程。删除元组“tup”后,最后一行代码中使用“print(tup)”输出元组“tup”的值时会出现系统错误。执行效果如图3-12所示。

图3-12 执行效果
3.2.4 实战演练——使用内置方法操作元组
在Python程序中,可以使用内置方法来操作元组,其中最为常用的方法如下表3-1所示。
表3-1

在下面的实例文件neizhi.py中,演示了使用以上4个内置方法操作元组的过程。

执行后效果如图3-13所示。

图3-13 执行效果
3.2.5 实战演练——将序列分解为单独的变量
在Python程序中,可以将一个包含n个元素的元组或序列分解为n个单独的变量。这是因为Python语法允许任何序列(或可迭代的对象)都可以通过一个简单的赋值操作来分解为单独的变量,唯一的要求是变量的总数和结构要与序列相吻合。在下面的实例文件fenjie.py中,演示了将序列分解为单独的变量的过程。

执行后的效果如图3-14所示。

图3-14 执行效果
如果是分解未知或任意长度的可迭代对象,上述分解操作是为其量身定做的工具。通常在这类可迭代对象中会有一些已知的组件或模式(如元素1之后的所有内容都是电话号码),利用“*”表达式分解可迭代对象后,使得开发者能够轻松利用这些模式,而无须在可迭代对象中做复杂的操作才能得到相关的元素。
在Python程序中,“*”表达式在迭代一个变长的元组序列时十分有用。在下面的实例文件xinghao.py中,演示了分解一个带标记元组序列的过程。在本实例中,在records中设置了分解方式的参考,然后分解并提取了line中的部分内容。

执行后的效果如图3-15所示。

图3-15 执行效果
3.2.6 实战演练——将序列中的最后几项作为历史记录
在Python程序中迭代处理列表或元组等序列时,有时需要统计最后几项记录以实现历史记录统计的功能。在下面的实例文件lishi.py中,演示了将序列中的最后几项作为历史记录的过程。

在上述代码中,对一系列文本行实现了简单的文本匹配操作,当发现有合适的匹配时就输出当前的匹配行,以及最后检查过的N行文本。deque(maxlen=N)创建了一个固定长度的队列。如果有新记录加入而使得队列变成已满状态时,会自动移除最老的那条记录。当编写搜索某项记录的代码时,通常会用到含有yield关键字的生成器函数,能够将处理搜索过程的代码和使用搜索结果的代码成功解耦。执行后的效果如图3-16所示。

图3-16 执行效果
3.2.7 实战演练——实现优先级队列
在Python程序中,使用内置模块heapq可以实现一个简单的优先级队列。在下面的实例文件youxianpy.py中,演示了实现一个简单的优先级队列的过程。

在上述代码中,利用heapq模块实现了一个简单的优先级队列,第一次执行pop()操作时返回的元素具有最高的优先级。拥有相同优先级的两个元素(foo和grok)返回的顺序,同插入队列时的顺序相同。
函数heapq.heappush()和函数heapq.heappop()分别将元素从列表_queue中实现插入和移除操作,并且保证列表中第一个元素的优先级最低。函数heappop()总是返回“最小”的元素,并且因为push和pop操作的复杂度都是O(logn),其中n代表堆中元素的数量,因此就算n的值很大,这些操作的效率也非常高。
上述代码中的队列以元组(-priority,index,item)的形式组成,将priority取负值是为了让队列能够按元素的优先级从高到低的顺序排列。这和正常的堆排列顺序相反,在一般情况下,堆是按从小到大的顺序进行排序的。
变量index的作用是为了将具有相同优先级的元素以适当的顺序排列。通过维护一个不断递增的索引,元素将以它们入队列时的顺序来排列。但是当index在对具有相同优先级的元素间进行比较操作时,同样扮演了一个重要的角色。执行后的效果如图3-17所示。

图3-17 执行效果
在Python程序中,如果以元组(priority,item)的形式来存储元素,只要它们的优先级不同,它们就可以进行比较。但是如果两个元组的优先级值相同,在进行比较操作时会失败。这时可以考虑引入一个额外的索引值,以(prioroty,index,item)的方式建立元组,因为没有哪两个元组会有相同的index值,所以这样就可以完全避免上述问题。一旦比较操作的结果可以确定,Python就不会再去比较剩下的元组元素了。在下面的实例文件suoyin.py中,演示了实现一个简单的优先级队列的过程。

在上述代码中,因为①~②行代码中没有添加索引,所以如果两个元组的优先级值相同时会出错。而在③~④行代码中添加了索引,这样就不会出错了。执行后的效果如图3-18所示。

图3-18 执行效果