Python3学习笔记 | 十六、Python的语句与语法-迭代器和解析(1)
- 2019 年 10 月 6 日
- 筆記
一、迭代器
1、初探
之前章节中,我们看到for语句可以Python任何序列类型,包括列表、元祖以及字符串。如下所示:
>>> for i in [1,2,3]:print(i,end=' ') ... 1 2 3 >>> for i in (1,2,3):print(i,end=' ') ... 1 2 3 >>> for i in '123':print(i,end=' ') ... 1 2 3
下面我们继续看文件迭代器、手动迭代(iter, next)、其它内置类型迭代器。
2、文件迭代器
回忆一下之前章节,文件访问方式有如下:
.read(): 一次性读取全部内容。
.readline(): 一次读取一行。
.readlines(): 生成列表,每一行是每个元素。
.next(): 跟readline()差不多,但读取完之后报错。 next()报错,为StopIteration。在Python中任何这类对象都认为是可迭代的。在Python里迭代工具(比如for)会调用next()来获取数据,并以StopIteration来确认何时离开。
for line in open(<filename>): print(line, end = '')
因为每个元素在最后包涵n(换行符),因此print函数结尾需要取消结尾中的换行。
注: 尽量不要使用readlines()函数,因为这个会一次性的把所有内容读取到内存里(转换为列表),运行速度会比较慢。最好使用readline或者迭代文件方法。
3、手动迭代
为了支持手动迭代代码,Python支持next()函数,它会自动读取next()函数。next(X)等同于X.next()。
f = open(<filename>) next(f)
这个会从第一行开始读取内容。
从技术角度来讲,迭代协议里,当使用for函数进行迭代时,会传递给iter内置函数,以便可迭代对象中获取迭代器。返回的对象有需要有next()方法。
>>> L = [1,2,3] >>> i = iter(L) >>> next(i) 1 >>> next(i) 2 >>> next(i) 3 >>> next(i) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
对于文件来说,不需要转换成iter类型的这一步:
>>> file = open(r'C:Testtest.txt') >>> file is iter(file) True
因为文件对象就是自己的迭代器,但列表,元祖,字符串等就不是了。
>>> str = '123' ; list = [1,2,3] ; tuple = (1,2,3) >>> str is iter(str) False >>> list is iter(list) False >>> tuple is iter(tuple) False
4、其他内置类型迭代器
除了文件以及像列表这样的实际的序列外,其它类型也有其适用的迭代器。例如,遍历字典键的经典方法是明确地获取其键的列表。
>>> dict = {'a': 1 ,'b' : 2 ,'c' : 3} >>> for key in dict.keys() : ... print(key,dict[key]) ... a 1 b 2 c 3
二、列表解析
1、初探
遍历列表时,使用for循环来修饰它:
>>> list = [1,2,3] >>> for i in range(len(list)) : ... list[i] += 10 ... >>> list [11, 12, 13]
这个是有效的,但不是“最佳实践”。我们可以使用产生所需结果列表的一个单个表达式来完成上面循环:
>>> list = [1,2,3] >>> list = [i + 10 for i in list] >>> list [11, 12, 13]
2、列表解析基础知识
从之前的例子开始分析:list1 = [i + 10 for i in list1]
这个先是运算 [i + 10 for i in list1]之后,再把此赋值给list1。我们来看里面是如何运算:
先是对list1进行迭代,每次把单个值符给i,再进行i + 10,成为新列表的单个元素。这个相当于:
tmp = [] for i in list1: tmp.append(i+10) list1 = tmp
可以认为是倒过来的for循环语句。
3、在文件上使用列表解析
>>> file = open(r'C:Testtest.txt').readlines() >>> file ['DoraEmonn', 'Daxiongn', 'JingXiang']
在这里发现,每行最后都会有n换行符,这个时候我们可以使用列表解析来进行去除换行符的操作。
>>> file = [line.strip() for line in file] >>> file ['DoraEmon', 'Daxiong', 'JingXiang']
或更简单
>>> file = [line.strip() for line in open(r'C:Testtest.txt')]
还可以进行更多操作:
>>> file = [line.strip().upper() for line in open(r'C:Testtest.txt')] >>> file ['DORAEMON', 'DAXIONG', 'JINGXIANG']
4、扩展的列表解析语法
扩展语法是在循环基础上,添加了条件:
>>> file = [line.strip().upper() for line in open(r'C:Testtest.txt') if line[0] !='J'] >>> file ['DORAEMON', 'DAXIONG']
在这里,发现添加 if line[0] != J’的时候,不显示以 “ J “ 开头的行。
>>> [x+y for x in [1,2,3] for y in [10,20,30]] [11, 21, 31, 12, 22, 32, 13, 23, 33]
我们会发现第二个for循环算是嵌套在第一个for循环。
三、其他迭代环境
map也可用在迭代中:
>>> list(map(str.upper, open(r'C:Testtest.txt'))) ['DORAEMONn', 'DAXIONGn', 'JINGXIANG']
map函数是把后面的可迭代的每个值当作前面的参数传入。在Python3开始正式引入map,之前版本,python2.7也可以使用,但map可以直接返回列表,不需要使用list函数进行转换。后续章节中会继续讲解。上面的可以如下解释:
>>> tmp = [] >>> for line in open(r'C:Testtest.txt'): ... tmp.append(str.upper(line)) ... >>> tmp ['DORAEMONn', 'DAXIONGn', 'JINGXIANG']
相应的,也有sorted,会对迭代对象进行排序后生成列表。
>>> sorted(open(r'C:Testtest.txt')) ['Daxiongn', 'DoraEmonn', 'JingXiang']
enumerate也会对迭代对象进行运算后,生成可迭代对象。
>>> list(enumerate(open(r'C:Testtest.txt'))) [(0, 'DoraEmonn'), (1, 'Daxiongn'), (2, 'JingXiang')]
enumerate就是在原有的顺序中添加序列号。除了这些,还有filter与reduce方法,这些再后续章节讲解用法。
>>> list(filter(bool,open(r'C:Testtest.txt'))) ['DoraEmonn', 'Daxiongn', 'JingXiang'] >>> import operator,functools >>> functools.reduce(operator.add,open(r'C:Testtest.txt')) 'DoraEmonnDaxiongnJingXiang'
sum、any、all、max、min也可使用迭代器。
any() 函数用于判断给定的可迭代参数 iterable 是否全部为 False,则返回 False,如果有一个为 True,则返回 True。元素除了是 0、空、FALSE 外都算 TRUE。
all() 函数用于判断给定的可迭代参数 iterable 中的所有元素是否都为 TRUE,如果是返回 True,否则返回 False。元素除了是 0、空、None、False 外都算 True。
>>> sum((1,2,3)),sum([4,5,6]) (6, 15) >>> any([1,[],'True']), all([1,[],'True']) (True, False) >>> max([2,3,1]),min([2,3,1]) (3, 1)
list, tuple, join 都是可以对可迭代对象进行操作后输出:
>>> list(open(r'C:Testtest.txt')),tuple(open(r'C:Testtest.txt')),'**'.join(open(r'C:Testtest.txt')) (['DoraEmonn', 'Daxiongn', 'JingXiang'], ('DoraEmonn', 'Daxiongn', 'JingXiang'), 'DoraEmonn**Daxiongn**JingXiang')
四、Python3中新的迭代环境
从Python3.x开始,更注重迭代。在Python2.x里,很多函数生成的是列表方式:
>>> zip('abc','123') [('a', '1'), ('b', '2'), ('c', '3')]
但在Python3.x开始是变成可迭代的特定对象:
>>> zip('abc','123') <zip object at 0x102295148> >>> list(zip('abc','123')) [('a', '1'), ('b', '2'), ('c', '3')]
Python 3.x的这种方式,会延迟计算,在提取内容的时候计算结果。这样会节省内存空间,不需要提前计算后放进内存里。迭代对象,当迭代完成之后,不能再次读取。
>>> a = list(zip('abc','123')) >>> for i in a: print(i, end=' ') ... ('a', '1') ('b', '2') ('c', '3') >>> >>> for i in a: print(i, end=' ') ... >>>
1、range
range从Python3.x开始变为迭代器。 Python 2.x:
>>> range(5) [0, 1, 2, 3, 4]
Python 3.x:
>>> range(5) range(0, 5)
所以,在Python 3.x要是需要生成一个有序列表,需要再次转换:
>>> list(range(5)) [0, 1, 2, 3, 4]
但也可以像列表一样使用:
>>> range(5)[1] 1 >>> range(5)[-1] 4
注:range可继续使用。
>>> r = range(7) >>> for i in r : ... print(i,end = ' ') ... 0 1 2 3 4 5 6 >>> >>> for i in r : ... print(i,end = ' ') ... 0 1 2 3 4 5 6 >>>
2、map、zip和filter
在Python3.x里,map、zip和filter也是使用迭代器来节约内存开销。但与range不同,使用一次之后,就不能再次使用。
>>> M = map(abs,(-1,3,7)) >>> list(M) [1, 3, 7] >>> list(M) [] >>> Z = zip((1,2,3),('a','b','c')) >>> list(Z) [(1, 'a'), (2, 'b'), (3, 'c')] >>> list(Z) [] >>> F = filter(bool,(1,'','True')) >>> list(F) [1, 'True'] >>> list(F) []
map() 函数会根据提供的函数对指定序列做映射。第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。
zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象,这样做的好处是节约了不少的内存。我们可以使用 list() 转换来输出列表。如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。
filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回一个迭代器对象,如果要转换为列表,可以使用 list() 来转换。该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。
五、多个迭代器 vs 单个迭代器
之前看到的range,可以同时使用多个迭代器。这个叫range有着多个迭代器。可以进行索引。但其它的,只能迭代一次。
后续章节会看到各种迭代器,而且会说明如何生成两种迭代器。
六、字典视图迭代器
字典视图迭代器,与其它多个迭代器相似(在Python2.x里还是使用列表)
>>> dict = {'a':1,'b':2,'C':3} >>> dict.keys() dict_keys(['a', 'b', 'C']) >>> dict.values() dict_values([1, 2, 3]) >>> dict.items() dict_items([('a', 1), ('b', 2), ('C', 3)])
在这里,迭代器都算是多个迭代器(Python3.4为基准)