1. 序列(sequence)
1.1 基本概念
序列是Python中最基本的⼀种数据结构。序列⽤于保存⼀组有序的数据,所有的数据在序列当中都有⼀个唯⼀的位置(索引)并且序列中的数据会按照 添加的顺序来分配索引 。
数据结构指计算机中数据存储的⽅式 。
1.2 序列的分类
序列类型按照是否能修改的角度进行分类:
可变序列(序列中的元素可以改变):例如 列表(list)字典(dict)。
不可变序列(序列中的元素不能改变):例如 字符串(str)元组(tuple)。
此外,还可以分为容器序列和扁平序列,其中:
容器序列有list(列表),tuple(元组),collection.deque(双端队列),这些序列能存放不同类型的数据。
扁平序列有str(字符串),bytes(字节序列),bytearray(字节数组),memoryview和array.array,这类序列只能容纳这一种类型。
容器序列存放的是他们所包含的任意类型的对象的引用,而扁平序列里存放的是值而不是引用,换句话说,扁平序列其实是已付按连续的内存空间。因此可见扁平序列其实更加紧凑,但是它里面只能存放诸如字符,字节和数值这种基础类型。
下图显示了可变序列和不可变序列的差异,同事也能看出前者从后者继承了一些方法。虽然内置的序列类型并不是直接从不可变序列和可变序列这两个抽象基类继承而来的,但是了解这些基类可以帮助我们总结出那些完整序列类型包含了哪些功能。
通过记住这些共有特性,把可变和不可变序列或是容器与扁平序列的概念融会贯通,在探索并学习的中学习新的序列类型时,你会更加得心应手。
最重要的也是最基础的序列类型应该就是列表了,列表是一个可变序列,并且能够同时存放不同类型的元素。
2.列表(list)
1.列表是Python中的一个对象,是包含若干元素的有序连续内存空间,当列表增减或删除元素时,列表对象自动进行内存的扩展和收缩,从而保证相邻元素之间没有缝隙。
同一个列表中元素的数据类型可以各不相同,可以同时包含整数,实数,字符串等基本类型的元素,也可以包含列表,元组,字典,集合函数以及其他任意对象。。如果只有一对方括号而没有任何元素则表示空列表。
2.列表的作用
(1)列表中可以保存多个有序的数据
(2)列表是用来存储对象的对象。
2.1列表的使用
列表的创建:
1,通过[]来创建一个空列表。
2,可以使用list()函数把元组,range对象,字符串,字典,集合或者其他可迭代对象转换为列表。需要注意的是,把字典转换为列表是默认是将字典的“键”转换为列表,而不是把字典的元素转换为列表,如果是想把字典的元素转换为列表,需要使用字典对象的items()方法明确说明,当然可以使用values()来明确说明要把字典的“值”转换为列表。
将元组转换为列表:
将range对象转换为列表
将字符串转换为列表
将集合转换为列表
将字典的键转换为列表
将字典的“键:值”对转换为列表
创建空列表
当列表不再使用的时候,可以使用del命令将其删除,这一点适用于所有类型的python对象。
3.建立由列表组成的列表
有时我们会需要初始化一个嵌套着几个列表的列表,譬如一个列表可能需要用来存放不同的学生名名单,或者是一个井字板上的一行方块。想要达到这些目的,最好的选择是使用列表推导。
示例1-1:一个包含3个列表的列表,嵌套的3个列表各自有3个元素来代表井字游戏的一行方块。
1.建立一个包含3个列表的列表,被包含的3个列表各自有3个元素,打印出这个嵌套列表。
2.把第1行第二列的元素标记为X,再打印出这个列表。
示例1-2展示了另一个方法,这个方法看上去是个有人的途径,但实际上它是错的。
含有3个指向同一对象的引用的列表是毫无用处的。
外面的列表其实包含3个指向同一个列表的作用。当我们不做修改的时候,看起来都还好。
一旦我们试图标记第一行和第二行的元素,就立马暴露了列表内3个指向同一个对象的事实。
实例1-2犯的错误的本质跟下面的的代码犯的错误一样:
追加同一个行对象(row)3次到达游戏板。
相反,示例1-1的方法等同于这样做:
每次迭代中都新建一个列表,作为新的一行(row)追加到游戏板(board)。只有第二行的元素被修改。
2.2列表元素访问
可以使用创建列表之后,可以使用整数下标来访问其中的元素,其中下标为0的元素表示第一个元素,下标为1的元素表示第二个元素,下标为2的元素表示第三个元素,以此类推。列表还支持使用负整数为下标,其中下标为-1的元素为倒数第一个元素,下标为-2的元素为倒数第二个元素,下标为-3的元素为倒数第三个元素。以此类推,如图所示:
2.3切片
1,切⽚是指从现有列表中获得⼀个⼦列表 。
2,通过切⽚来获取指定的元素。
3,语法: 列表[起始 : 结束 : 步⻓]。
4,通过切⽚获取元素时,会包括起始位置的元素,不会包括结束位置的元素。
5,起始位置和结束位置的索引可以不写。
(1)如果省略结束位置, 则会从当前的开始位置⼀直截取到最后。
(2)如果省略开始位置, 则会从第⼀个元素截取到结束的元素,但是不包括结束的元素。
(3)如果开始位置和结束位置都省略, 则则会从第⼀个元素开始截取到最后⼀个元素。
6,步⻓表示每次获取元素的间隔,默认是1(可以省略不写)
7,步⻓不能是0,但可以是是负数,
8.使用切片可以获取列表的部分元素
通过切片可以返回列表中的部分元素组成的新列表。与使用索引作为下标访问列表元素的方法不同,切片操作不会因为下标越界而抛出异常。而是简单的在列表尾部阶段或者返回一个空间,代码具有更强的健壮性。
aList[::]:返回包含原列表中所有元素的新列表
aList[::-1]:返回包含原列表中所有元素的逆序列表
aList[::2]:隔一个取一个,获取偶数位置的元素
aList[1::2]:隔一个取一个,获取奇数位置的元素
aList[3:6]:指定切片开始和结束的位置
aList[0:100]:切片结束位置大于列表长度时,从列表尾部截断
aList[100:]:切片开始位置大于列表长度时,返回空列表
aList[-15:3]:进行必要的截断处理
aList[3:-10:-1]:位置3在位置-10的右侧,-1表示反向切片
aList[3:-5]:位置3在位置-5的左侧,正向切片
9.使用切片可以为列表增加元素
可以使用切片操作在列表任意位置插入新元素,不影响对象的内存地址,属于原地操作。
在列表尾部加入元素
在列表头部插入元素
在列表中间插入元素
10.使用切片可以替换和修改列表中的元素。
替换列表元素,等号两边的列表长度相等
切片连续,等号两边的列表长度可以不相等。
隔一个修改一个
序列解包的方法
map,filter,zip对象都支持这样的用法
切片不连续时等号两边列表的长度必须相等
11.使用切片删除列表中的元素。
删除列表中前3个元素
>>> aList = [3,5,7,9]
>>> aList[:3] = []
>>> aList
[9]
另外,也可使用del命令与切片截个来删除列表中的部分元素,并且切片元素可以不连续。
切片元素连续
>>> aList=[3,5,7,9,11]
>>> del aList[:3]
>>> aList
[9, 11]
切片元素不连续,隔一个删一个
>>> aList = [3,5,7,9,11]
>>> del aList[::2]
>>> aList
[5, 9]
12.切片得到的是列表的浅复制。
切片返回的是列表元素的浅复制,与列表对象的直接复制并不一样。
切片,浅复制
>>> aList = [3,5,7]
>>> bList=aList[::]
两个列表值相等
>>> aList = [3,5,7]
>>> bList=aList[::]
>>> aList==blist
浅复制,不是同一个对象
>>> aList = [3,5,7]
>>> bList=aList[::]
>>> aList==bList
True
两个列表的地址不相等
>>> id(aList)==id(bList)
False
相同的值在内存中只有一份
>>> id(aList[0])==id(bList[0])
True
修改bList列表元素的值不会影响aList
>>> bList[1]=8
>>> bList
bList的值没有发生改变
>>> bList
[3, 8, 7]
aList的值没有发生改变
>>> aList
[3, 5, 7]
如果列表中包含列表或其他可变的序列,情况会变得复杂些
>>> x=[[1],[2],[3]]
>>> y=x[:]
>>> y
[[1], [2], [3]]
直接修改y中下标为0的元素值,不影响x
>>> y[0]=[4]
>>> y
[[4], [2], [3]]
通过列表对象的方法原地增加元素
>>> y[1].append(5)
>>> y
[[4], [2, 5], [3]]
列表x也收到同样的影响
>>> x
[[1], [2, 5], [3]]
13.为什么切片和区间会忽略最后一个元素?
14.给切片赋值
3. 通⽤操作
1.+ 和 *
(1)+ 可以将两个列表拼接成⼀个列表,也可以是实现列表增加元素的目的,但这个运算符不属于原地操作,而是指挥家新列表,并且涉及大量元素的复制,效率非常低。使用复合赋值运算符+=实现列表追加元素时属于原地操作,与append()方法一样高效。
连接两个列表
内存地址发生改变
为列表追加元素
内存地址不变
(2)* 可以将列表重复指定的次数 (注意2个列表不能够做乘法,要和整数做乘法运算),从一定程度上来说也可以实现为列表增加元素的功能。与加法运算符一样,该运算符也适用于元素和字符串。另外,运算符*=也可以用于列表元素重复,与运算符+=一样属于原地操作。
元素重复,返回新列表
地址发生改变
元素恢复原地进行
地址不变
重复0次,清空
2.in 和 not in
3.in⽤来检查指定元素是否在列表当中,查询时间随列博鳌增加长度的增加而线性增加,而同样的操作对于集合而言则是常数级的。
4.not in ⽤来检查指定元素是否不在列表当中
5.len() 获取列表中元素的个数
6.max() 获取列表中最⼤值
7.min() 获取列表中最⼩值
8.list.index(x[, start[, end]])
(1)第⼀个参数 获取指定元素在列表中的位置
(2)第⼆个参数 表示查找的起始位置
(3)第三个参数 表示查找的结束位置
如果该元素不存在列表中则抛出异常。
9.list.count(x) 统计指定元素在列表中出现的个数
元素3在列表中x出现的次数
不存在,返回0
元素2在列表x中首次出现的索引
列表x中没有5,抛出异常。
10.sum()函数用于将多个列表中元素之和
11.len()函数用于返回列表中元素的个数
12.zip()函数用于将多个列表中的元素重新组合为元组并返回这些元组的zip对象
13.enumerate()函数返回包含若干下标和值得迭代对象
14.map()函数把函数映射到列表上的每个元素
15.filter()函数根据指定函数的返回值对列表元素进行过滤
16.all()函数用来测试列表中是否所有元素都等价于True
17.any()函数用来测试列表中是否有等价于True的元素
示例:
生成列表
x=list(range(11))
打乱列表中元素的顺序
测试是否所有元素都等价于True
测试是否存在等价于True的元素
返回最大值
按指定规则返回最大值
所有元素之和
列表元素个数
多列表元素重新组合
zip()函数也可以用于一个序列或迭代对象
如果两个列表不等长,则以短的为准
枚举列表元素,返回enumerate对象
enumerate对象可以转换为列表,元组,集合
4. 修改列表
1.通过切⽚来修改(起始就是给切⽚的内容重新赋值,但是赋值的内容必须是⼀个序列)
2.当设置了步⻓时,序列中元素的个数必须和切⽚中元素的个数保持⼀致
3.通过切⽚来删除元素
(1)del list[起始 : 结束]
(2)list = []
5. 列表的⽅法
1.append() 像列表的最后添加⼀个元素
2.insert(arg1,arg2) 像列表指定位置插⼊⼀个元素 参数1:要插⼊的位置 参数2:要插⼊的元素
3.extend(iterable) 使⽤⼀个新的序列来扩展当前序列(它会将该序列的中元素添加到列表中) 参数需要传递⼀个序列
这三个方法属于原地操作,不影响列表对象在内存中的起始地址。对于长列表而言,使用Insert()方法在列表首部或中间插入元素时效率较低。如果确实需要在首部按序插入多个元素,可以现在尾部追加,然后使用reverse()进行翻转,或者考虑使用标准库collections中的双端队列deque对象提供的appendleft()方法。
查看对象的内存地址
在尾部追加元素
在指定位置插入元素
在尾部插入元素
列表在内存中的地址不变
4.pop() 根据索引删除并返回指定元素
5.remove() 删除指定元素 (如果相同值的元素有多个,只会删除第⼀个)
6.clear()清空列表里的所有元素。
弹出并返回尾部元素
弹出并返回指定位置的元素
删除所有的元素
删除首个值为2的元素
删除指定位置上的元素
必须强调的是,由于列表具有内存自动收缩和扩张的功能,在列表中间的位置插入或删除元素时,不仅效率低,而且该位置后面所有元素在列表中的索引也会发生变化。
这三个方法属于原地操作,不影响列表对象的内存地址。另外,还可以使用命令del删除列表中的指定元素,这个方法同样属于原地操作。
7.reverse() 翻转列表
8.sort(key=None,reverse=False) ⽤来对列表中的元素进⾏排序 reverse:True反序;False 正序,默认升序。
列表对象的sort()和reverse()分别对列表进行原地排序和逆序,没有返回值。所谓“原地”,意思是用处理后的数据替换原来的数据,列表的首地址不变,列表中元素原来的顺序全部丢失。
包含11个整数的列表
把列表x中的元素随机乱序
按转换成字符串以后的长度降序排列
按转换成字符串以后的大小升序排序
按默认规则排序
把所有元素翻转或逆序
如果不想丢失原来的顺序,可以使用sorted()和reversed()。其中,内置函数sorted()返回排序后的新列表,参数Key和reverse的含义与列表方法sort()完全相同,内置函数reversed()返回一个逆序后的reversed对象。充分利用列表对象的sort()方法和内置函数sort()的key参数,可以实现更加复杂的排序。
9.copy()返回猎豹的浅复制。所谓浅复制,是指生成的新的列表,并且把原列表中的只包含整数,实数,复数等基本类型的元组,字符串这样的不可变类型的数据,一般是没有问题的。但是,如果原列表中包含列表之类的可变数据类型,由于浅复制只是把子列表之类的可变数据类型,由于浅复制时只把字列表的应用复制到新列表中,余世修改任何一个都会影响另外一个。
原列表中包含子列表
浅复制
两个列表中的内容看起来完全一样
为新列表中的子列表追加元素
整数,实数等不可变类型不受此影响。
在新列表尾部追加元素
原列表不受影响
列表对象的copy()方法和切片操作以及标准库copy()函数一样都是返回浅复制,如果想避免上面代码演示的问题,可以使用标准库copy中的deepcopy()函数实现深复制。所谓深复制,是指对原列表中的元素进行递归,把所有的值都复制到新列表中,对嵌套的子列表不再是复制作用。这样一来,新列表和原列表是互相独立的,修改任意一个都不会影响另外一个。
深复制
为原列表中的子列表追加元素
在新列表尾部追加元素
不论是浅复制还是深复制,与列表对象的直接复制都是不一样的情况。下面的代码把同一个列表复制给两个不同的变量,这两个变量是互相独立的,修改任何一个都不会影响另外一个。
把同一个列表对象赋值给两个变量
修改其中一个列表的子列表
不影响另外一个列表
下面的代码演示的是另外一种情况。把一个列表变量赋值给另外一个变量,这样两个变量指向同一个列表对象,对其中一个做任何修改都会立刻在另一个变量得到体现。
两个变量指向同一个列表
对x做的任何修改,y都会受到影响。
6. 遍历列表
6.1 for循环
通过for循环来遍历列表
注意: for循环的代码块会执⾏多次,序列中有⼏个元素就会执⾏⼏次。每执⾏⼀次就会将序列中的⼀个元素赋值给变量,所以我们可以通过变量来获取列表中的元素
6.2 range(start, stop[, step])
参数说明
1.start: 计数从 start 开始。默认是从 0 开始。例如range(5)等价于range(0, 5);
2.stop: 计数到 stop 结束,但不包括 stop。例如:range(0, 5) 是[0, 1, 2, 3, 4]没有5
3.step:步⻓,默认为1。例如:range(0, 5) 等价于 range(0, 5, 1)
7.列表推导和生成器表达式
7.1列表推导
列表推导式也称为列表解析式,可以使用非常简洁的方式对列表或其他可迭代对象的元素进行遍历,过滤或再次计算,快速生成满足特定的新列表,代码非常简洁,具有很强的可读性,是python程序开发时最多的技术之一。Python的内部实现对列表推导式做了大量的优化,可以保证很快的运行速度,也是推荐使用的一种技术。列表推导式的语法形式为:
[expression for expr1 in sequence1 if condition1
for expr2 in sequence2 if condition2
for expr3 in sequence3 if condition3
......
for exprN in sequenceN if conditionN]
列表推导式在逻辑上等价于一个循环结构,只是形式上更加简洁,例如:
aList = [x * x for x in range(10)]
相当于:
aList = []
for xin range(10):
aList.append(x*x)
再如:
freshfruit = ['banana','loganberry','passion fruit']
aList = [w.strip()for win freshfruit]
等价于下面的代码:
aList = []
for itemin freshfruit:
aList.append(item.strip())
当然也等价于:
aList = list(map(lambda x:x.strip(),freshfruit))
或:
aList =list(map(str.strip,freshfruit))
大家应该听说过一个故事,说的是阿凡提(也有的说是阿基米德)与国王比赛下棋,国王说要是自己输了阿凡提,想要什么他都可以拿出来。阿凡提说那就要点米吧,棋盘一共64个小格子,在第一个格子放1粒米,第二个格子放2粒米,第三个格子放4粒米,第四个格子放8粒米。以此类推,后面每个格子的米都是前一个格子的两倍,一直把64个格子都放满,那么到底要多少粒米呢?使用列表推导式再结合内置函数sum()就很容易知道答案。
sum([2**i for i in range(64)])
答案:18446744073709551615
按照一斤大米月26000粒算,为放满棋盘,需要大概3500亿吨大米,结果可想而知,最后国王没办法拿出那么多米。
下面再通过几个示例进一步展示列表推导式的强大功能:
1.实现嵌套列表的平铺
>>> vec = [[1,2,3],[4,5,6],[7,8,9]]
>>> [num for elem in vec for num in elem]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
在这个列表推导式中有两个循环,其中第一个循环可以看做外循环,执行的慢,第二个循环可以看做内循环,执行的快,上面代码的执行过程等价于下面的写法。
vec = [[1,2,3],[4,5,6],[7,8,9]]
result = []
for elem in vec:
for num in elem:
result.append(num)
print(result)
当然,这里演示的只是一层嵌套列表的平铺,如果有多级嵌套或者不同子列表前天深度不同,就不能使用上面的方法了。这是,可以使用函数递归实现:
def flatList(lst):
result = []#存放最终结果的列表
def nested(lst):#函数嵌套定义
for itemin lst:
if isinstance(item,list):
nested(item)#递归子列表
else:
result.append(item)#扁平化列表
return(lst)# 调用嵌套定义的函数
return result #返回结果
2.过滤不符合条件的元素
在列表推导式中可以使用if子句对列表中的元素进行筛选,只在结果列表中保留符合条件的元素。下面的代码可以列出当前文件夹下的左右Python源文件:
>>> [filename for filename in os.listdir('.') if filename.endswith(('.py','.pyw'))]
['Hello.py', 'jjcc.py']
下面的代码用于列表中选择符合条件的元素组成新的列表:
>>> aList = [-1,-4,6,7.5,-2.3,9,-11]
>>> [i for i in aList if i>0] #所有大于0的数字
[6, 7.5, 9]
再如,已知有一个包含一些同学成绩的字典,现在需要计算所有成绩的最高分,最低分,平均分,并查找所有最高分的同学,代码可以这样写:
>>> scores = {"Zhang San":45,"Li Si":78,"Wang Wu":40,"Zhou Liu":96,
... "Zhao Qi":65,"Sun Ba":90,"Zhang Jiu":78,"Wu Shi":99,
... "Dong Shiyi":60}
>>> highest=max(scores.values()) #最高分
>>> lowest=min(scores.values()) #最低分
>>> average = sum(scores.values())/len(scores) #平均分
>>> highest,lowest,average
(99, 40, 72.33333333333333)
>>> heightPerson=[name for name,score in scores.items() if score==highest]
>>> heightPerson
['Wu Shi']
与下面的代码功能类似,下面的代码使用列表推导式查找列表中最大元素的所有位置:
>>> from random import randint
>>> x = [randint(1,10) for i in range(20)]
>>> x
[2, 4, 4, 7, 10, 10, 7, 3, 8, 3, 5, 2, 7, 9, 1, 1, 10, 10, 9, 7] #20个介于[1,10]的整数
>>> m=max(x)
>>> [index for index,value in enumerate(x) if value==m] #最大整数的所有出现位置
[4, 5, 16, 17]
3.同时遍历多个列表或可迭代对象
>>> [(x,y) for x in [1,2,3] for y in [3,1,4] if x!= y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
>>> [(x,y) for x in [1,2,3] if x==1 for y in [3,1,4] if y!=x]
[(1, 3), (1, 4)]
对于包含多个循环的列表推导式,一定要清楚多个循环的执行顺序或“嵌套关系”。例如:上面第一个列表推导式等价于:
>>> result = []
>>> for x in [1,2,3]:
... for y in [3,1,4]:
... if x!=y:
... result.append((x,y))
...
>>> result
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
4.使用列表推导式实现矩阵转置
>>> matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
>>> result = []
>>> for i in range(len(matrix[0])):
... result.append([row[i] for row in matrix])
>>> result
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
对于嵌套了列表推导式的列表推导式,一定要清楚其执行程序。例如,上面的列表推导式的执行过程等价于下面的代码:
>>> matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
>>> result = []
>>> for i in range(len(matrix[0])):
... result.append([row[i] for row in matrix])
...
>>> result
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
如果把内层的列表推导式也展开,完整的执行过程可以通过下面的代码来模拟:
>>> matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
>>> result = []
>>> for i in range(len(matrix[0])):
... temp = []
... for row in matrix:
... temp.append(row[i])
... result.append(temp)
>>> result
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
当然,也可以使用内置函数zip()和list()来实现矩阵转置
>>> list(map(list,zip(*matrix)))
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
5.列表推导式中可以使用函数或复杂表达式
>>> def f(v):
... if v%2 == 0:
... v = v**2
... else:
... v=v+1
... return v
...
>>> print([f(v) for v in [2,3,4,-1] if v>0])
[4, 4, 16]
6.列表推导式支持文件对象迭代
with open('文件路径‘,'r') as fp:
print([line for line in fp])
7.使用列表推导计算笛卡尔积
如果你需要一个列表,列表里是3种不同尺寸的T恤衫,每个尺寸有两个颜色。
>>> colors = ['black','white']
>>> sizes = ['S','M','L']
>>> tshirts = [(color,size) for color in colors for size in sizes]
>>> tshirts
[('black', 'S'), ('black', 'M'), ('black', 'L'), ('white', 'S'), ('white', 'M'), ('white', 'L')]
>>> for color in colors:
... for size in sizes:
... print((color,size))
...
('black', 'S')
('black', 'M')
('black', 'L')
('white', 'S')
('white', 'M')
('white', 'L')
>>> tshirts = [(color,size) for size in sizes for color in colors]
>>> tshirts
[('black', 'S'), ('white', 'S'), ('black', 'M'), ('white', 'M'), ('black', 'L'), ('white', 'L')]
7.2生成器表达式
虽然也可以用列表推导来初始化元元组,数组或其它序列类型,但是生成器表达式是更好的选择,这是因为生成器表达式背后遵守了迭代器协议,可以逐个产生元素,而不是先建立一个完整的列表,然后再把这个列表传递到某个构造函数里。前面这种方式显然可以节省内存。
生成器表达式的语法跟列表推导式差不多,只不过把方括号改成圆括号而已。
示例1-1展示了如何用生成器表达式建立元组和数组:
>>> symbols = '$@#$%^'
>>> tuple(ord(symbol) for symbol in symbols)
(36, 64, 35, 36, 37, 94)
>>> import array
>>> array.array('I',(ord(symbol) for symbol in symbols))
array('I', [36, 64, 35, 36, 37, 94])
使用生成器表达式去计算笛卡尔积
>>> colors = ['black','white']
>>> sizes = ['S','M','L']
>>> for tshirt in ('%s %s' % (c,s) for c in colors for s in sizes):
... print(tshirt)
输出结果:
black S
black M
black L
white S
white M
white L
生成器表达式会逐个产生元素,从来不会一次性产生一个含有6个T恤样式的列表。
8.参考书籍
《流畅的python》 Luciano Ramalho 著 中国工信出版社集团
《python程序设计基础(第2版)》 董付国 著 清华大学出版社