
4.2 Tuple(元组)
Tuple又叫元组,是一个线性结构,它的表达形式是这样的:

即用一个圆括号括起来的一串对象就可以创建一个Tuple,之所以说它是一个线性结构是因为在元组中元素是有序的,比如我们可以这样去访问它的内容:

这段代码会输出:

这里可以看到,我们通过“[]”运算符直接访问了Tuple的内容,这个运算符在上一章已经见过了,但是没有深入讲解。这里先详细学习切片操作符,因为它是一个非常常用的运算符,尤其在Tuple和List中应用广泛。
4.2.1 切片
1.背景
切片操作符和C/C++的下标运算符非常像,但是在C/C++中,“[]”只能用来取出指定下标的元素,所以它在C/C++中叫作下标运算符。
在Python中,这个功能被极大地扩展了——它不但能取一个元素,还能取一串元素,甚至还能隔着取、倒着取、反向取等。由于取一串元素的操作更像是在切片,所以我们称它为切片操作符。
灵活使用切片操作符,往往可以大大简化代码,这也是Python提供的便利之一。
2.取一个元素
如果有一个Tuple,并且我们想取出其中一个元素,可以使用具有一个参数的下标运算符:

绝大部分编程语言下标都是从0开始的,也就是说在Python中对于一个有n个元素的Tuple,自然数下标的范围是0~n-1。
所以这里会输出tuple1中下标为2的第3个元素:

这是切片操作符最简单的形式,它只接收一个参数就是元素的下标,也就是上面例子里的2。
特别地,Python支持负数下标表示从结尾倒着取元素,比如如果想取出最后一个元素:

但是要注意的是负数下标是从-1开始的,所以对于一个含有n个元素的Tuple,它的负数下标范围为-1~-n,因此这里得到的是下标为4的最后一个元素,输出为:

如果我们取了一个超出范围的元素:

那么Python解释器会抛出一个IndexError异常:

这个异常的详细信息是下标超出了范围。如果遇到这种情况,需要检查一下代码是不是访问了不存在的下标。
3.取连续的元素
先看一个例子:

这段代码会输出:

我们会发现结果仍然是一个Tuple,由第1个到第4个元素之间的元素构成,其中包含第1个元素,但是不包含第4个元素。
这种切片操作接收两个参数,开始下标和结束下标,中间用分号隔开,也就是上面例子中的0和3,但是要注意的是元素下标区间是左闭右开的。如果对之前讲循环时候的range还有印象的话,可以发现它们的区间都是左闭右开的,这是Python中的一个规律。
特殊地,如果从第0个元素开始取,或者要一直取到最后一个,我们可以省略相应的参数,比如:

第一句表示从第1个元素取到第3个元素,第二句表示从第4个元素取到最后一个元素,所以输出为:

同样地,这里也可以使用负下标,比如:

表示从第1个元素取到倒数第2个元素,所以输出为:

4.以固定间隔取连续的元素
上述取连续元素的操作其实还可以进一步丰富,比如下面这个例子:

这段代码会输出:

这里表示的含义就是从第2个元素取到第5个元素,每2个取第1个元素。于是我们取出了第2个和第4个元素。这也是切片操作符的完整形式,即[开始:结束:间隔],例如上面的[1:4:2]。
特殊地,这个间隔可以是负数,表示反向间隔,例如:

这句代码会输出:

可以看出就是翻转了整个Tuple。
4.2.2 修改
这里说的“修改”并不是原位的修改,因为Tuple的元素一旦指定就不可再修改,而是通过创建一个新的Tuple来实现修改,比如下面这个例子:

这段代码会输出:

可以看到我们通过创建tuple3和tuple4,“修改”了tuple1和tuple2。
同时要注意的是,之前在讲字符串的时候提到的加法和乘法对Tuple的操作也是类似的,效果分别是两个Tuple元素合并为一个新的Tuple和重复自身元素返回一个新的Tuple。
4.2.3 遍历
遍历有两种方法:

这段代码会输出:

这里,在print函数中加了一个使结束符为空的参数,这个用法会在下一章函数中讲到,这里只要知道这样会使print不再自动换行就可以了。
我们可以通过一个for循环或者while循环直接顺序访问元组的内容。显然for循环不仅可读性高而且更加简单,在大多数情况下应该优先采用for循环。
另外值得一提的是,之所以Tuple可以这样用for遍历是因为Tuple包括后面马上要提到的List和Dict对象本身是可迭代的对象,这个概念之后会细讲,这里只要学会for循环的用法就可以了。
4.2.4 查找
在Tuple中查找元素可以用in,比如:

这段代码会输出:

in是一个使用广泛的用于判断包含的运算符,类似地还有not in。in的作用就是判断特定元素是否在某个对象中,如果包含就返回True,否则返回False。
4.2.5 内置函数
此外有一些内置函数可以作用于Tuple上,比如:

从上到下分别是求tuple1的长度、tuple1中最大的元素、tuple2中最小的元素。
这些函数对接下来即将讲到的List和Dict也有类似的作用。