《Think Python 2e》学习精粹(十二):元组
- 元组是一组值的序列,是一种内置数据类型;
1、元组是不可变的
-
元组中的值可以是任意类型, 使用整数索引;
-
元组中的值用逗号隔开,元组通常用括号括起来,创建单一元素元组时,需要在结尾处添加一个逗号;
>>> t1 = 'a', 'b', 'c', 'd', 'e' >>> t2 = ('a', 'b', 'c', 'd', 'e') >>> t3 = 'a',
-
另一个创建元组的方法是使用内建函数
tuple
;-
在没有参数传递时,创建一个空元组;
>>> t = tuple() >>> t ()
-
如果实参是一个序列(字符串、列表或者元组),结果将是一个包含序列内元素的元组;
>>> t = tuple('lupins') >>> t ('l', 'u', 'p', 'i', 'n', 's')
-
因为
tuple
是内建函数名,所以应该避免将它用作变量名;
-
-
列表的大多数操作符同样也适用于元组;
- 方括号运算符将索引一个元素;
- 切片运算符选取一个范围内的元素;
-
元组是不可变的,元组的元素(item)不能更新;
>>> t = ('a', 'b', 'c', 'd', 'e') >>> t[0] 'a' >>> t[1:3] ('b', 'c') >>> t[0] = 'A' TypeError: object doesn't support item assignment
-
可以使用其他元组替换现有元组;
>>> t = ('A',) + t[1:] >>> t ('A', 'b', 'c', 'd', 'e')
-
关系型运算符也适用于元组和其他序列, Python 会首先比较序列中的第一个元素,如果它们相等,就继续比较下一组元素,以此类推,直至比值不同,其后的元素(即便是差异很大)也不会再参与比较;
>>> (0, 1, 2) < (0, 3, 4) True >>> (0, 1, 2000000) < (0, 3, 4) True
2、元组赋值
-
可以同时为元组中的一组变量赋值,左侧的变量数和右侧值的数目必须相同,一般来说,右侧可以是任意类型(字符串、列表或者元组)的序列;
>>> a, b = b, a >>> a, b = 1, 2, 3 ValueError: too many values to unpack >>> addr = 'monty@python.org' >>> uname, domain = addr.split('@') >>> uname 'monty' >>> domain 'python.org'
split
函数返回的对象是一个包含两个元素的列表;
3、元组作为返回值
-
严格地说,一个函数只能返回一个值(包括元组),其效果等同于返回多个值;
>>> t = divmod(7, 3) >>> t (2, 1)
4、可变长度参数元组
- 函数可以接受可变数量的参数, 以 “*” 开头的形参将输入的参数 汇集 到一个元组中,汇集形参可以使用任意名字,但是习惯使用
args
; - 与汇集相对的,是 分散(scatter) , 如果你有一个值序列,并且希望将其作为多个参数传递给一个函数, 可以使用运算符*;
5、列表和元组
-
zip
是一个内建函数,可以接受将两个或多个序列组(字符串、列表、元组等),并返回一个元组列表, 其中每个元组包含了各个序列中相对位置的一个元素;>>> s = 'abc' >>> t = [0, 1, 2] >>> zip(s, t) <zip object at 0x7f7d0a9e7c48> >>> for pair in zip(s, t): ... print(pair) ... ('a', 0) ('b', 1) ('c', 2)
-
zip
对象是迭代器的一种,即任何能够按照某个序列迭代的对象, 迭代器在某些方面与列表非常相似,但不同之处在于,无法通过索引来选择迭代器中的某个元素; -
为了使用列表操作符和方法,你可以用
zip
对象创建一个列表,如果用于创建的序列长度不一,返回对象的长度以最短序列的长度为准;>>> list(zip(s, t)) [('a', 0), ('b', 1), ('c', 2)] >>> list(zip('Anne', 'Elk')) [('A', 'E'), ('n', 'l'), ('n', 'k')]
-
可以在
for
循环中使用元组赋值,遍历包含元组的列表;t = [('a', 0), ('b', 1), ('c', 2)] for letter, number in t: print(number, letter)
-
如果将
zip
、for
循环和元组赋值结合起来使用,你会得到一个可以同时遍历两个(甚至多个)序列的惯用法;
6、字典和元组
-
字典有一个叫做
items
的方法,其结果是一个dict_items
对象,它返回由多个元组组成的序列,其中每个元组是一个键值对; -
dict_items
对象,这是一个对键值对进行迭代的迭代器,可以在for
循环中使用它,由于是字典生成的对象,这些项是无序的;>>> d = {'a':0, 'b':1, 'c':2} >>> t = d.items() >>> t dict_items([('c', 2), ('a', 0), ('b', 1)]) >>> for key, value in d.items(): ... print(key, value) ... c 2 a 0 b 1
-
可以使用元组的列表初始化一个新的字典;
>>> t = [('a', 0), ('c', 2), ('b', 1)] >>> d = dict(t) >>> d {'a': 0, 'c': 2, 'b': 1}
-
将
dict
和zip
结合使用,可以很简洁地创建一个字典;>>> d = dict(zip('abc', range(3))) >>> d {'a': 0, 'c': 2, 'b': 1}
-
字典的
update
方法也接受元组列表,并将其作为键值对添加到已有的字典中去; -
在字典中使用元组作为键(主要因为无法使用列表)的做法很常见;
7、序列嵌套
- 在很多情况下,不同类型的序列(字符串、列表、元组)可以互换使用;
- 字符串比其他序列的限制更多,因为它的所有元素都必须是字符,且字符串不可变,如果你希望能够改变字符串中的字符,使用列表嵌套字符或许更合适;
- 列表比元组更常用,主要是因为它们是可变的,但是有些情况下,更倾向于使用元组;
- 在一些情况下(例如
return
语句),从句式上生成一个元组比列表要简单; - 如果使用一个序列作为字典的键,那么你必须使用元组或字符串这样的不可变类型;
- 如果向函数传入一个序列作为参数,那么使用元组可以降低由于别名而产生的意外行为的可能性;
- 由于元组的不可变性,它们没有类似(
sort
) 和 (reverse
)这样修改现有列表的方法, Python 提供了内建函数sorted
和reversed
,前者可以接受任意序列,并返回一个正序排列的新列表,后者则接受一个序列,返回一个可逆序迭代列表的迭代器;
- 在一些情况下(例如
8、调试
- 列表、字典和元组都是数据结构 (data structures);
- 复合数据结构(compound data structures):列表嵌套元组,以及使用元组作为键、列表作为值的字典;
- 复合数据结构非常实用,但是使用时容易出现所谓的形状错误(shape errors),也就是由于数据结构的类型、大小或结构问题而引发的错误;
- 可以从 http://thinkpython2.com/code/structshape.py 下载
structshape
模块,它提供了一个同名函数,可以接受任意类型的数据结构作为实参,然后返回一个描述它形状的字符串,在追踪数据结构的类型上遇到了困难,可以使用structshape
来帮助分析。
(本篇起,学习精粹和作业实现系列均为用 Typora 离线编辑,格式会有差异)