和大多数编程语言类似,Python也有很多内建数据结构,用来表示一系列有关联或者类似的数据。获取元素的方法也类似,都是通过下标,即[]包含的数字,用来找到每一个位置的元素,下标是从0开始。但是和大多数编程语言不同的是,Python的数据结构可以存储不同数据类型,而其他语言类型必须保持一致。下标方面,Python有一大特色功能,就是切片,而且Python下标支持负数索引,-1指定最后一个元素,往前类推。

元组

一种固定长度、不可变的对象序列,通过小括号或者tuple关键字创建元组对象。元组可以通过加法乘法得到新的元组对象,把内容相加或乘以多份。元组在Python中很多地方都会用到,包括函数返回多个值的时候,实质上返回的是一个元组,以及同时给多个变量赋不同的值,本质上也是将右边的值打包成元组。
注意的是,元组本身的元素是不可变的,但是如果元组包含的是引用的值的话,可以去改变引用所指向的值,而不会产生错误。

  1. a = (1, 2, 3) # 或者a = tuple([1, 2, 3])
  2. b = a * 2 # (1, 2, 3, 1, 2, 3)
  3. c = (1, [2, 3])
  4. c[2].append(4) # 正确的
  5. print(c) # (1, [2, 3, 4])

元组拆包

元组的数据除了通过下标索引的方式获取元素,还可以根据元组的个数,一次性赋给相同个数的变量。还可以通过在变量前增加*来获取不定长的元素。

  1. a = (1, 2, 3)
  2. b, c, d = a # b == 1, c == 2, d == 3
  3. e, *f = a # e == 1, f == (2, 3)

元组方法

因为元组不可变,所以方法相对比较少,一个常见方法是count,计算元组中某一个元素的出险次数。

  1. a = (1, 1, 2, 2, 2, 3, 4)
  2. a.count(2) # 3

列表

一种可变长、元素可变的对象序列,通过中括号或者list关键字创建列表对象。

  1. a = [1, 2, 3] # 或者a = list([1, 2, 3])

增加和移除元素

append方法可以在列表最后添加一个元素,insert方法可以在指定位置添加元素,这两个相比,insert方法明显更加方便,但是在内存消耗更高。
pop方法用来移除某一位置的元素,同时函数会返回元素值,remove方法用来移除特定内容的元素,如果有重复的元素,会移除第一个对应元素。
通过in和not in可以判断某一元素是否在列表中。

连接和联合列表

列表也可以通过加法连接多个列表,因为列表是可变的,所以可以通过extend方法将一个列表里的所有值添加到另一个列表里去。使用extend方法会比直接连接消耗更少的内存。

排序

通过调用sort方法可以根据给定的比较方法对列表进行排序,这个操作是原地完成的。

*二分搜索和已排序列表的维护

bisect模块提供了二分搜索的一些方法,其中bisect方法可以在已排序列表中查找元素应当查找的位置,insort方法将元素插入到相应的位置。
注意的是,这个模块并不会检查列表是否已经排序完成,所以需要在编程的时候注意。

切片

通过在索引的时候使用[start:stop:step]获得列表中某一部分的元素,包含start不包含stop,不提供start表示从列表第一个开始取,不提供stop表示取到列表最后一个,step表示每隔多少个进行取值,这三者都可正可负。

内建序列函数

enumerate

根据列表元素生成迭代器,每次遍历同时获得元素及元素索引。

  1. a = ['a', 'b', 'c']
  2. for i, c in enumarate(a):
  3. print('num: {}, letter: {}'.format(i,c))
  4. # num: 1, letter: 'a'
  5. # num: 2, letter: 'b'
  6. # num: 3, letter: 'c'

sorted

根据列表返回新建已排序列表,和列表的sort方法不同,sorted需要接受一个列表作为参数,并且会返回一个新列表,而不是在原地进行排序。

zip

将多个列表元素按序配对成元组,元组个数跟最短列表的长度一致,返回由这些元组组成的列表。

  1. a = [1, 2, 3]
  2. b = ['a', 'b', 'c']
  3. c = [True, False]
  4. d = zip(a, b, c) # [(1, 'a', True), (2, 'b', False)]

reversed

将一个序列元素倒序排列,并返回一个生成器,可以用来生成列表或者进行循环。

字典

dict的每个元素都是由键值对组成,可以通过dict方法创建字典对象,虽然字典输出时会以大括号形式输出,但是不能使用大括号进行创建。一个字典的键都是唯一的,它通过索引获取值的时候,下标不是元素的位置,而是元素对应的键。可以通过del或者pop根据键删除对应的值,pop方法会返回相应的值。可以用in检查是否包含某个键。
keys方法和values方法返回键和值的迭代器,顺序不是特定的但是两者的顺序会是一致的。
update方法可以合并新的字典内容,如果有相同的键,原来的值会被覆盖。

从序列生成字典

比较直接的方法是使用zip方法合并两个序列,分别指定为键和值。

默认值

获取字典值的时候,可以设置默认值,用来给新添加的键赋默认值。

有效的字典键类型

字典的键本质上是以哈希的方式进行存储,所以字典的键必须得满足能够被哈希化,在能够作为字典的键,这就要求字典的键必须是不可变的。

集合

一种无序且元素唯一的容器,可以通过set方法或者大括号创建集合对象。集合支持数学上关于集合的大部分操作,包括交集、并集、补集等。

函数 替代方法 描述
a.add(x) - 将元素x加入元素a
a.clear() - 将集合重置为空,清空所有元素
a.remove(x) - 从集合a移除某个元素
a.pop() - 移除任意元素,如果集合是空的抛出KeyError
a.union(b) a | b a和b中的所有不同元素
a.update(b) a |= b 将a的内容设置为a和b的并集
a.intersection(b) a & b a、b中同时包含的元素
a.intersection_update(b) a &= b 将a的内容设置为a和b的交集
a.difference(b) a - b 在a不在b的元素
a.difference_update(b) a -= b 将a的内容设为在a不在b的元素
a.symmetric_difference(b) a ^ b 所有在a或b中,但不是同时在a、b中的元素
a.symmetric_difference_update(b) a ^= b 将a的内容设为所有在a或b中,但不是同时在a、b中的元素
a.issubset(b) - 如果a包含于b返回True
a.issuperset(b) - 如果a包含b返回True
a.isdisjoint(b) - a、b没有交集返回True

列表、集合和字典的推导式

Python的奇技淫巧语言特性之一,通过推导式可以快速生成序列对象。本质上是一个循环语句块。

列表推导式:[expr for val in collection (if condition)] 字典推导式:{key_expr : value_expr for value in collection (if condition)} 集合推导式:{expr for val in collection (if condition)}

嵌套列表推导式

可以通过多个for循环做到对复杂序列遍历得到所需结构,也可以将表达式也替换成推导式生成多维序列。嵌套方法比较方便,但是相对来说牺牲了一定的可读性。