在《手把手陪您学Python》20——列表中,我们学习了列表的定义以及列表的各种操作方法。今天我们要学习的元组,可以被看做是不能修改的列表。所谓不能修改,就是不能像列表一样进行增删改的操作,而查的切片和索引方式,以及一些函数和方法与列表还是非常类似的,所以今天的内容比较容易理解,大家加油。
1、元组的定义
元组也是Python中一种常用的数据结构,它是用小括号括起来的一组数据序列。和列表一样,元组中的元素既可以是数字、布尔值、字符串、列表、变量等数据类型,也可以是包括上述元素的列表或者元组,形成多层的嵌套。同时,元组的打印结果也是用小括号括起来的元组。
In [1]: tup1 = (1, 'a', [1, 'a']) # 元组元素是数字、字符串、列表
tup1
Out[1]: (1, 'a', [1, 'a'])
In [2]: tup2 = (1, 'a', [1, 'a'], tup1) # 元组元素是数字、字符串、列表和变量,同时变量又是一个元组,形成嵌套
tup2
Out[2]: (1, 'a', (1, 'a'), [1, 'a'])
In [3]: tup3 = () # 与定义空列表的方法类似,也可以定义空元组
tup3
Out[3]: ()
有了学习列表的基础,元组的定义很容易理解,但有一点是需要大家注意,首先我们看一个列子。
In [4]: tup4 = (1)
tup4
Out[4]: 1
乍一看,大家觉得可能没什么问题,但请注意一下输出的结果,是一个数字,而不是一个元组。这是因为元组的标识符()与数学符号中的小括号是一样的,所以当元组只有一个元素时,程序会优先将()识别为数学符号而不是一个元组的标识符。如果要表示只有一个元素的元组,需要在这个元素后面增加一个“,”号,程序就会将其识别为元组了。
In [5]: tup5 = (1,)
tup5
Out[5]: (1,)
这里再介绍一种更为便捷的定义元组的方法,就是在定义元组时,不需要加上(),直接写上用逗号分隔的元组的元素就行,包括定义只有一个元素的元组时也适用,但定义空元组依然要保留()。
In [6]: tup6 = 1, 'a', [1, 'a']
tup6
Out[6]: (1, 'a', [1, 'a'])
In [7]: tup7 = 1,
tup7
Out[7]: (1,)
2、元组的切片与索引
元组切片与索引的方法与列表完全相同,甚至我们的示例都可以完全沿用《手把手陪您学Python》20——列表中切片与索引的示例,只要把列表的中括号[],改为元组的小括号()就可以了。这里就不再列举了,请大家关注公众号回复关键词“手20”,下载示例文件,自己在Jupyter Notebook中尝试一下。
至此,关于切片与索引的方法,我们已经在字符串、列表和元组中都应用到了。之前说过,切片和索引的方法也是Python中较为高阶的规则,所以在不同的数据结构中都会应用到。甚至我们以后介绍数据分析库Numpy和Pandas时,更为复杂的一维数组Serise,和多维数组ndarray,也会采用同样的索引和切片方法。所以,真心希望大家能够将切片与索引的方法和原理弄清楚/。
大家可以移步阅读《手把手陪您学Python》7——字符串的索引、《手把手陪您学Python》8——字符串的切片两篇文章,里面对于字符串切片与索引的方法介绍得非常清楚。而这些方法也同样适用于列表、元组以及我们后面要介绍的很多可以切片和索引的数据类型。
3、元组的修改
看到标题大家会不会觉得有点奇怪,一上来就说元组是不能修改的,为什么还要介绍元组的修改呢?
如果大家有这样的想法是完全正确的,因为元组的元素既不能增加、也不能修改、更不能删除,就像下面的例子一样。
In [8]: tup8 = (1, 'a', [2, 'b'], True, (1, 2))
tup8[2] = 'c'
Out[8]: ---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-8-e82c6ece0e57> in <module>
1 tup8 = (1, 'a', [2, 'b'], True, (1, 2))
----> 2 tup8[2] = 'c'
TypeError: 'tuple' object does not support item assignment
In [9]: tup8.append(3) # extend方法大家也可以试一下
Out[9]: ---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-9-3c81a69e7b35> in <module>
----> 1 tup8.append(3) # extend方法大家也可以试一下
AttributeError: 'tuple' object has no attribute 'append'
删除这里要说明一下,不能删除是指不能删除元组中的单个或者部分元素,但是可以删除整个元组。
In [10]: tup8.remove(1) # 不能删除单独的元素
Out[10]: ---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-10-980a7164a12b> in <module>
----> 1 tup8.remove(1) # 不能删除单独的元素
AttributeError: 'tuple' object has no attribute 'remove'
In [11]: del tup8[1:2] # 也不能删除部分元素
Out[11]: ---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-11-af48f07d8ff8> in <module>
----> 1 del tup8[1:2] # 也不能删除部分元素
TypeError: 'tuple' object does not support item deletion
In [12]: del tup8 # 但可以删除整个元组
tup8
Out[12]: ---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-12-051c53383cee> in <module>
1 del tup8 # 但可以删除整个元组
----> 2 tup8
NameError: name 'tup8' is not defined
但严格来说,所谓不能修改是指元组元素的数值或内存地址是不能修改的,但地址映射的对象本身是可以被修改的。也就是说,虽然元组的元素不能被修改,如果元组的元素本身是可变的,那么在这个元素的内部是可以进行修改。这是什么意思,让我们通过一个例子看一下。
In [13]: tup8 = (1, 'a', [2, 'b'], True, (1, 2))
tup8[2][1] = 'c'
tup8
Out[13]: (1, 'a', [2, 'c'], True, (1, 2))
在上面In[8]示例中,我们看到,将tup8[2],也就是[2, 'b']这个列表,进行修改是不行的。这是因为[2, 'b']是元组的一个元组,它的内存地址是确定,而且不能被修改的。但在上面In[13]这个例子中,我们没有对元组元素,也就是这个列表的内存地址进行修改,而是将这个地址映射的对象内部进行了修改。就好像元组中的列表是一个袋子,只要这个袋子不变,至于袋子里面的东西如何变化,元组是不管的。
这是元组可以被“修改”的一种情况,讲出来就是为了让大家了解这种可能性,但需要牢记的,还是元组不能被“修改”的特性。
4、元组的运算
元组的运算方法也与列表相同,继续沿用上一篇的实例,看一下元组的几种运算方法。
In [14]: (1, 2, 3) + (4, 5, 6)
Out[14]: (1, 2, 3, 4, 5, 6)
In [15]: (1, 2, 3) * 3
Out[15]: (1, 2, 3, 1, 2, 3, 1, 2, 3)
In [16]: (1, 2, 3) == (1, 2, 3)
Out[16]: True
In [17]: (1, 2, 3) != (1, 2, 3)
Out[17]: False
In [18]: (2, 2, 3) > (1, 2, 2, 4)
Out[18]: True
In [19]: 1 in (1, 2, 3)
Out[19]: True
In [20]: 1 not in (1, 2, 3)
Out[20]: False
In [21]: (1, 2, 3) is (1, 2, 3)
Out[21]: True
5、元组的方法和函数
因为元组的元素不能被修改,涉及元组的方法和函数非常有限,而且都是和列表一样的。所以,这里仅列出几个常用的元组的方法和函数。
In [22]: tup9 = (1, 1, 2, 3, 4, 5, 6)
In [23]: len(tup9)
Out[23]: 7
In [24]: max(tup9)
Out[24]: 6
In [25]: min(tup9)
Out[25]: 1
In [26]: tup9.count(1)
Out[26]: 2
In [27]: tup9.index(3)
Out[27]: 3
此外,还有一组将列表和元素进行相互转换的函数,有点类似于在整数、字符串、浮点之间转换的函数int()、float()、str()。
In [28]: list(tup9)
Out[28]: [1, 1, 2, 3, 4, 5, 6]
In [29]: lst = [1, 1, 2, 3, 4, 5, 6]
tuple(lst)
Out[29]: (1, 1, 2, 3, 4, 5, 6)
其实,tuple()函数包括list()函数,起到的不仅仅是上例所示的相互转化的作用,更准确来说,这两个函数是可以将任何可以被迭代的数据序列转化成元组或者列表的。“迭代”是我们在《手把手陪您学Python》18——循环语句for中重点介绍的概念,如果大家不太清楚,可以点击上方链接查看。
因为我们讲过,字符串也是可以被迭代的,因此,tuple()和list()可以将字符串转化成元组或者列表,而字符串中的每一个字符,就是元组或者列表的一个个元素。但str()函数并不能反向地将由一个个字符组成的元组或者列表再转化成之前的字符串,具体的形式,我们看下面的例子就知道了。
In [30]: a = 'Python'
In [31]: tuple(a)
Out[31]: ('P', 'y', 't', 'h', 'o', 'n')
In [32]: list(a)
Out[32]: ['P', 'y', 't', 'h', 'o', 'n']
In [33]: str(tuple(a)) # 元组包括()成为一个字符串
Out[33]: "('P', 'y', 't', 'h', 'o', 'n')"
In [34]: str(list(a)) # 列表包括[]成为一个字符串
Out[34]: "['P', 'y', 't', 'h', 'o', 'n']"
6、元组的作用
上面说了很多元组这也不行(不能增删改),那也不行(没有什么可用的函数和方法)的话。但元组真的就“不行”么?当然不是了,而且不仅不是“不行”,反而非常有用,特别是它不能被修改的特性,就像一个天然的“代码保护器”,可以使我们编写的代码更加安全稳定,不容易被修改。所以,在应用一些不需要被修改的序列时,大家要首选元组作为这种序列的数据类型,而不是列表。
7、元组的拆包
说完元组的作用,为其“平反”之后,我们就来看看元组一个非常重要的应用——拆包。
很早之前我们介绍过“赋值”,就是将等号右边的值赋值给等号左边的变量。那时候我们介绍的是一个值赋值给另一个变量。如果要给多个变量赋值的话,就需要多条语句来实现。但有了元组的拆包功能之后,我们就可以通过一条语句,同时给多个变量赋值,而且不限数据类型。
In [35]: a, b, c, d, e = 1, 'a', [2, 'b'], True, (1, 2) # 这是介绍元组定义时介绍的不加()定义元组的方法,在给多个变量赋值时,这种形式也更直观
print(a, b, c, d, e)
Out[35]: 1 a [2, 'b'] True (1, 2)
如果使用*rest这个特殊语法格式,还可以实现任意长度的拆包。当然rest这个名称没有什么特殊意义,很多Python程序员更喜欢使用*_来表示不想要的变量,但要注意最后的结果是列表。
In [36]: tup = 1, 2, 3, 4, 5
a, b, *_ = tup
In [37]: a, b # 相当于不加()的给元组的定义,所以输出结果是元组
Out[37]: (1, 2)
In [38]: _
Out[38]: [3, 4, 5]
“拆包”的第一种应用是遍历元组或列表组成的序列:
In [39]: seq = [(1, 2, 3), (4, 5, 6), (7, 8, 9)]
for a, b, c in seq:
print("a={}, b={}, c={}".format(a, b, c))
Out[39]: a=1, b=2, c=3
a=4, b=5, c=6
a=7, b=8, c=9
“拆包”的第二种应用是从函数返回多个值,这个等我们讲到自定义函数的时候再详细说明。
以上就是对Python元组的讲解了,虽然从目前来看,我们应用到元组的机会并不多,但后面大家在编写程序时,可以有意识地多使用元组代替过去使用列表的部分场景,比如在for循环的迭代器中就可以使用元组来代替列表。
下一篇将要给大家介绍的是一种非常重要的数据类型——字典。字典的数据结构以及展示形式与我们之前学习的列表、元组都不一样,因此给我们带来了更多的数据操作的自由度和可能性,敬请关注。
感谢阅读本文!如有任何问题,欢迎留言,一起交流讨论^_^
欢迎扫描下方二维码,关注“亦说Python”公众号,阅读《手把手陪您学Python》系列文章的其他篇目,或点击下方链接直达。
《手把手陪您学Python》3——PyCharm的安装和配置
《手把手陪您学Python》5——Jupyter Notebook
For Fans:关注“亦说Python”公众号,回复“手21”,即可免费下载本篇文章所用示例语句。
