一. 内置序列类型
Python 标准库用 C 实现了丰富的序列类型:
-
容器序列:能存放不同类型数据的序列,如
list
、tuple
和collections.deque
; -
扁平序列:只能容纳一种类型的序列,如
str
、bytes
、bytearray
、memoryview
和array.array
;
容器序列存放的是它们所包含的任意类型对象的引用,而扁平序列存放的是值而不是引用。
换句话说,扁平序列是一段连续的内存空间。由此可见扁平序列其实更加紧凑,但是它里面只能存放诸如字符、字节和数值这种基础类型。
序列类型还能按照能否被修改来分类:
-
可变序列:
list
、bytearray
、array.array
、collections.deque
和memoryview
; -
不可变序列:
tuple
、str
、bytes
下图很好地描述了可变序列 MultableSequence
和不可变序列 Sequence
的差异:
Python 的序列中,最基础也是最重要的序列类型就是 list
了,list
是一个可变的容器序列,下面我们开始学习列表推导和生成器表达式。
二. 列表推导和生成器表达式
列表推导是构建 list
的快捷方式,而生成器表达式则可以用来创建其它任何类型的序列。
列表推导
例 1 把字符串转换为 Unicode 码位列表
>> symbols = '河南挺住,南京加油!'
>> codes = [ord(symbol) for symbol in symbols]
>> codes
[27827, 21335, 25402, 20303, 65292, 21335, 20140, 21152, 27833, 65281]
通常,我们只用列表推导来创建新的列表,并且尽量保持简洁。如果列表推导超过了 2 行,应该使用 for
循环代替。
例 2 Python3 中列表推导不再有变量泄露的问题
>> x = 'ABC'
>> L = [x.lower() for x in x]
>> L
['a', 'b', 'c']
>> x
'ABC'
列表推导、生成器表达式,以及集合推导和字典推导,在 Python3 中都有自己的局部作用域。表达式内部的变量和赋值只在局部起作用,表达式的上下文里的同名变量可以被正常引用,局部变量并不会影响到它们。
列表推导同 filter
和 map
的比较
列表推导可以帮助我们把一个一个序列或是其它可迭代类型中的元素过滤或是加工,然后再新建一个列表。Python 内置的 filter
和 map
函数组合起来也能达到这一效果,但无论是性能还是可读性上打了不小的折扣。
例 3 用列表推导和 map
filter
组合来创建相同的 list
>> symbols = '河南挺住,南京加油!'
>> beyond_unicode = [ord(symbol) for symbol in symbols if ord(symbol) > 21335]
>> beyond_unicode
[27827, 25402, 65292, 27833, 65281]
上述使用列表推导实现的元素加工和过滤操作,如果交给内置的 map
和 filter
来实现,将会非常晦涩:
>> beyond_unicode = list(filter(lambda x: x>21335, map(ord, symbols)))
>> beyond_unicode
[27827, 25402, 65292, 27833, 65281]
笛卡尔积
笛卡尔积是一个列表,列表里的元素是由输入的可迭代类型的 元素对
组成的元组,因此笛卡尔积列表的长度等于输入变量长度的乘积。
例 3 使用列表推导计算笛卡尔积
>> colors = ['black', 'white']
>> sizes = ['M', 'L', 'XL']
>> tshirts = [(color, size) for size in sizes for color in colors]
>> tshirts
[('black', 'M'),
('white', 'M'),
('black', 'L'),
('white', 'L'),
('black', 'XL'),
('white', 'XL')]
生成器表达式
虽然可以用列表推导来初始化元组、数组或其它序列类型,但是生成器表达式是最好的选择。这是因为生成器表达式背后遵循了迭代器协议,可以逐个产出元素,而不是先建立一个完整的列表,然后再把这个列表传递到某个构造函数里。
生成器表达式相比列表推到可以更多地节约内存,防止发生 memory leak。
例 4 用生成器表达式初始化元组和数组
>> symbols = '河南挺住,南京加油!'
>> tuple(ord(symbol) for symbol in symbols)
(27827, 21335, 25402, 20303, 65292, 21335, 20140, 21152, 27833, 65281)
>> import array
>> array.array('I', (ord(symbol) for symbol in symbols))
array('I', [27827, 21335, 25402, 20303, 65292, 21335, 20140, 21152, 27833, 65281])
例 5 使用生成器表达式计算笛卡尔积
>> colors = ['black', 'white']
>> sizes = ['M', 'L', 'XL']
>> tshirts = ((color, size) for size in sizes for color in colors)
>> tshirts
<generator object <genexpr> at 0x0000021B5AA8F200>
运行结果:
>> next(tshirts)
('black', 'M')
>> next(tshirts)
('white', 'M')
>> next(tshirts)
('black', 'L')
>> next(tshirts)
('white', 'L')
>> next(tshirts)
('black', 'XL')
>> next(tshirts)
('white', 'XL')
>> next(tshirts)
StopIteration: