列表解析式、生成器、迭代器及可迭代对象的区别和应用
2018-04-06 20:43
681 查看
导文
语法糖(Syntactic sugar)列表生成式(list comprehension)
生成器(generator)
迭代器(iterator)
可迭代对象(iterable)
Iterable、Iterator与Generator之间的关系
语法糖
语法糖(Syntactic sugar),是由Peter J. Landin(和图灵一样的天才人物,是他最先发现了Lambda演算,由此而创立了函数式编程)创造的一个词语,它意指那些没有给计算机语言添加新功能,而只是对人类来说更“甜蜜”的语法。语法糖往往给程序员提供了更实用的编码方式,有益于更好的编码风格,更易读。在python语言中语法糖有三元表达式、列表生成式、列表生成器、迭代器等等,具体可参考如下博客:
https://segmentfault.com/a/1190000006261012[/code]解析式通用语法
For constructing a list, a set or a dictionary Python provides special syntax called “displays”, each of them in two flavors:
为构造一个列表、集合或者字典,python提供了称谓”显式”的特殊语法,每种语法都有两种形式
1、either the container contents are listed explicitly
容器内容被明确列出(即普通常用的列表)
2、they are computed via a set of looping and filtering instructions, called a comprehension
它们通过一组循环和过滤指令来计算,称为生成式
Common syntax elements for comprehensions are:
语法格式如下:
comprehension ::= expression comp_for
comp_for ::= “for” target_list “in” or_test [comp_iter]
comp_iter ::= comp_for | comp_if
comp_if ::= “if” expression_nocond [comp_iter]
The comprehension consists of a single expression followed by at least one for clause and zero or more for or if clauses.
生成式是由单个表达式后紧跟至少一个for语句和多个或0个if语句列表生成式
列表定义
A list display is a possibly empty series of expressions enclosed in square brackets:
list_display ::= “[” [starred_list | comprehension] “]”生成式语法
基础语法格式
[expr for iter_var in iterable] 即 [返回值 for 元素 in 可迭代对象]
工作过程:
- 迭代iterable中的每个元素;
- 每次迭代都先把结构赋值给iter_var,然后通过exp得到一个新的返回值;
- 最后将返回值形成一个新的列表。
代码示范:#!/bin/python3 #-*- coding: UTF-8 -*- lst = [x*x for x in range(1,6)] print(lst) 运行结果: [1, 4, 9, 16, 25]条件语法格式
[expr for item in iterable if cond1 if cond2]
工作过程:
迭代iterable中的每一个元素,然后对每个元素进行if条件判断,当有多个if时,if条件相当于if cond1 and if cond 2
将迭代的结果复制给item,然后通过expr表达式计算出返回值
将返回值形成新的列表
代码示范:#!/bin/python3 #-*- coding: UTF-8 -*- lst = [x for x in range(1,20) if x>=10 if x%2==0] print(lst) 运行结果: [10, 12, 14, 16, 18]嵌套循环语法
[expr for i in iterable1 for j in iterable2 ]
工作过程:
迭代iterable1中的第一个元素后,进入下一轮for循环迭代iterable2中的每一元素,interable2循环完成后,再次进入iterable1中的第二个元素,以此类推。
把迭代结果赋值给iter_var,荣光expr得到返回值
10a95
最后将返回值形成新的对象list
代码示范:#!/bin/python3 #-*- coding: UTF-8 -*- lst0 = [(x,y) for x in 'abc' for y in range(2)] lst1 = [[x,y] for x in 'abc' for y in range(2)] lst2 = [{x,y} for x in 'abc' for y in range(2)] print(lst0) print(lst1) print(lst2) 运行结果: [('a', 0), ('a', 1), ('b', 0), ('b', 1), ('c', 0), ('c', 1)] [['a', 0], ['a', 1], ['b', 0], ['b', 1], ['c', 0], ['c', 1]] [{0, 'a'}, {1, 'a'}, {0, 'b'}, {1, 'b'}, {0, 'c'}, {1, 'c'}]列表生成式经典习题
返回1-10平方的列表
代码示范:#!/bin/python3 #-*- coding: UTF-8 -*- lst = [x**2 for x in range(1,11)] print(lst) 运行结果: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]有一个列表lst = [1,4,9,16,2,5,10,15]
生成新列表,要求新列表元素是lst相邻2项的和
代码示范:#!/bin/python3 #-*- coding: UTF-8 -*- lst = [1,4,9,16,2,5,10,15] lstnew = [lst[i]+lst[i+1] for i in range(len(lst)-1)] print(lstnew) 运行结果: [5, 13, 25, 18, 7, 15, 25]打印九九乘法表
考点
- 严格按照工作过程和列表解析式的定义,套用至少一个for循环或多个for循环
- for循环必须是连续在一起的,for循环不能分开
正确示范代码:#!/bin/python3 #-*- coding: UTF-8 -*- lst = [print("{}*{}={:<3}{}".format(j,i,j*i,"\n" if i==j else ""),end="") for i in range(1,10) for j in range(1,i+1)] print(lst) 运行结果: 1*1=1 1*2=2 2*2=4 1*3=3 2*3=6 3*3=9 1*4=4 2*4=8 3*4=12 4*4=16 1*5=5 2*5=10 3*5=15 4*5=20 5*5=25 1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36 1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49 1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64 1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
切忌for j循环写入format中,如果将j循环写入format中时,违反了代码语法:[expr for iter_val in iterable for iter_val in iterable],若违反代码语法肯定报错,根据工作过程知道,首先进行循环i,迭代到1时,返回给expr表达式print(),print的返回值构成新的列表。
另外:最后一个for循环表示要出现的次数,下面错误代码中示范的案例表明只会出现10个相乘的数,因此和题意完全不符,
错误示范代码:#!/bin/python3 #-*- coding: UTF-8 -*- lst = [print("{}*{}={:<3}{}".format(j,i,j*i,"\n" if i==j else ""),end="") for i in range(1,10) for j in range(1,i+1)] print(lst) 运行结果: SyntaxError: Generator expression must be parenthesized if not sole argument SyntaxError:如果不是唯一参数,则必须将生成器表达式加括号“0001.abadicddws”是ID格式
要求ID格式是以点号分割,左边是4为从1开始的整数,右边是10位随机小写英文字母,请依次生成前100个ID的列表#!/bin/python3 #-*- coding: UTF-8 -*- import random string = "abcdefghigklmnopqrstuvwsyz" lst = ["{:04}.{}".format(i,"".join(string[random.randint(0,25)] for j in range(10))) for i in range(1,4)] print(lst) 运行结果: ['0001.mgdpsgtcqa', '0002.kduzdfncds', '0003.itohqzghzk']代码对比说明问题
#嵌套正确代码 string = "abcdefghigklmnopqrstuvwsyz" lst = ["{:04}.{}".format(i,"".join(string[random.randint(0,25)] for j in range(10))) for i in range(1,4)] print(lst) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #嵌套非正确代码 lst = ["{}*{}".format(i,j for j in range(1,i+1)) for i in range(1,10)] print(lst) #嵌套说明问题 当生成i*j个的expr表达式时,嵌套for时,两个for时兄弟并联关系 当生成i个expr表达式的值时,在expr表达式内可以可以嵌套for循环,但是expr表达式内的for循环和语法糖中的for循环毫无关系列表高阶函数经典
将字典转换成元组组成的列表
lst={‘Tom’:15,’Jerry’:18,’Peter’:13}#!/bin/python3 #-*- coding: UTF-8 -*- dic = {'Tom':15,'Jerry':18,'Peter':13} lst = [(x,y) for x,y in dic.items()] print(lst) 运行结果: [('Jerry', 18), ('Tom', 15), ('Peter', 13)]把列表中所有字符转换小写,非字符串元素保留原样
lst = [‘TOM’,’Peter’,10,’Jerry’]#!/bin/python3 #-*- coding: UTF-8 -*- lst = ['TOM','Peter',10,'Jerry'] lst0 = [x.lower() if isinstance(x,str) else x for x in lst] lst1 = list(map(lambda x:x.lower() if isinstance(x,str) else x,lst)) print(lst0) print(lst1) 运行结果: ['tom', 'peter', 10, 'jerry'] ['tom', 'peter', 10, 'jerry']把列表中所有的字符串转换小写,非字符串元素移除
lst = [‘TOM’,’Peter’,10,’Jerry’]#!/bin/python3 #-*- coding: UTF-8 -*- lst = ['TOM','Peter',10,'Jerry'] lst0 = [x.lower() for x in lst if isinstance(x,str)] lst1 = list(map(lambda x:x.lower(),filter(lambda x: isinstance(x,str),lst))) print(lst0) print(lst1) 运行结果: ['tom', 'peter', 'jerry'] ['tom', 'peter', 'jerry']生成器(generator)
生成器定义
A function which returns a generator iterator. It looks like a normal function except that it contains yield expressions for producing a series of values usable in a for-loop or that can be retrieved one at a time with the next() function.
返回生成器迭代器的函数。 它看起来像一个普通的函数,只是它包含yield表达式,用于生成一系列可用于for-loop的值,或者可以使用next()函数一次检索一个值。生成器迭代器
generator iterator
An object created by a generator function,Each yield temporarily suspends processing, remembering the location execution state (including local variables and pending try-statements). When the generator iterator resumes, it picks-up where it left-off (in contrast to functions which start fresh on every invocation).
生成器迭代器是通过生成器生成的一个对象,每次遇到yield时会暂停生产值并记住位置,当再次遇到迭代时它会在从暂停的位置重新开始,
其实生成器就是迭代器中的一种表现形式但是不同的对象,而且都是可迭代对象,后面有实验证明[在迭代器判断中],生成器的构成
生成器的构成是通过两种方式:
- 使用类似列表的方式生成
具体信息如下:
1.语法格式(返回值 for 元素 in 可迭代对象 if条件)
2.列表解析式的中括号换成小括号即可
3.返回一个生成器
- 使用包含yield的函数来生成
通常情况下对应简单的列表等采用列表生成器,若遇到复杂的计算值采用yield函数构成。生成器的执行过程与特性
执行过程:
在执行过程中,遇到yield关键字就会终端执行,下次继续从中断位置开始执行。
特性:
1.与列表解析式截然不同,列表解析式是立即返回一个完整的列表,生成器表达式是按需计算,惰性求值,需要是才进行求值;
2.遇到yield记录当前位置,下次从记录位置继续执行
3.从前到后走完一遍后,不能回头生成器值的访问方式
通过内置next()方法
使用循环方式进行迭代
调用生成器对象send()方法实例说明
生成器表访问
代码及特性示范1:#!/bin/python3 #-*- coding: UTF-8 -*- g = ("{:04}".format(i) for i in range(1,6)) print(next(g)) for x in g: print(x) print('~~~~~~~~~~~~') for x in g: print(x) 运行结果: 0001 0002 0003 0004 0005 ~~~~~~~~~~~~生成器表达式返回值构成列表
代码示范2:
expr表达式返回值构成列表或生成器,若无返回值时反回NoneTpye#!/bin/python3 #-*- coding: UTF-8 -*- #val的值是什么? #val=first+second语句之后能否再next()? g = (print('{}'.format(i+1)) for i in range(2)) first = next(g) second = next(g) val = first + second print(val) print(next(g)) 运行结果: 1 2 Traceback (most recent call last): File "./gen.py", line 9, in <module> val = first + second TypeError: unsupported operand type(s) for +: 'NoneType' and 'NoneType'生成器的next不能回头
代码示范3:#!/bin/python3 #-*- coding: UTF-8 -*- #val的值是什么? #val=first+second语句之后能否再next()? g = (x for x in range(10) if x % 2) #取奇数1,3,5,7,9 first=1 second=3 val=4 下一个为5 first = next(g) second = next(g) val = first + second print(val) print(next(g)) 运行结果: 4 5列表解析式和生成器对比
计算方式
生成器表达式延迟计算,列表解析式立即计算内存占用
但从返回值本身来说,生成器表达式省内存,列表解析式返回新的列表
生成器没有数据,内存占用极少
列表解析式构造新的列表需要占用内存计算速度
单看计算时间,生成器表达式耗时非常短,列表解析式耗时长
生成器本身并没有返回值,只返回一个生成器对象,虽然是返回值但是累加起来占用内存和列表生成式几乎相等
列表解析式构造并返回一个新的列表实验论证
#!/bin/python3 #-*- coding: UTF-8 -*- import datetime import sys start = datetime.datetime.now() lst = [ x for x in range(10000000) ] delta = (datetime.datetime.now() - start).total_seconds() print("列表解析式耗时:{}".format(delta)) print("列表解析式耗内存:{}".format(sys.getsizeof(lst))) start0 = datetime.datetime.now() lst = ( x for x in range(10000000) ) delta0 = (datetime.datetime.now() - start0).total_seconds() print("列表生成式耗时:{}".format(delta0)) print("列表生成式耗内存:{}".format(sys.getsizeof(lst))) start1 = datetime.datetime.now() def test_gen(start,end): for x in range(start,end): yield x lst =test_gen(0,10000000) delta1 = (datetime.datetime.now() - start1).total_seconds() print("列表生成器函数耗时:{}".format(delta1)) print("列表生成器函数耗内存:{}".format(sys.getsizeof(lst))) 运行结果: 列表解析式耗时:0.328316 列表解析式耗内存:81528056 列表生成式耗时:0.104485 列表生成式耗内存:88 列表生成器函数耗时:1.2e-05 列表生成器函数耗内存:88可迭代对象
可直接用于for循环的对象统称为可迭代对象(Iterable)
判断是否是可迭代对象,用函数isinstance()#!/bin/python3 #-*- coding: UTF-8 -*- from collections import Iterable print(isinstance("abc",Iterable)) print(isinstance("[]",Iterable)) print(isinstance("{}",Iterable)) print(isinstance("()",Iterable)) print(isinstance("(x,for x in range(2))",Iterable)) 运行结果: True True True True True迭代器
迭代器定义
An object representing a stream of data. Repeated calls to the iterator’s next() method (or passing it to the built-in function next()) return successive items in the stream. When no more data are available a StopIteration exception is raised instead. At this point, the iterator object is exhausted and any further calls to its next() method just raise StopIteration again.
表示数据流的对象。 重复调用迭代器的next ()方法(会返回流中的连续项。直到没有数据可以返回时抛出StopIteration异常错误。可以把这个数据流看做一个有序序列,但我们无法提前知道这个序列的长度。同时,Iterator的计算是惰性的,只有通过next()函数时才会计算并返回下一个数据。迭代器判断
通过定义及判断可知,生成器也是迭代器,但是不是同一个对象,通过type返回值不一样#!/bin/python3 #-*- coding: UTF-8 -*- from collections import Iterator print(isinstance("abc",Iterator)) print(isinstance("()",Iterator)) print(isinstance((x for x in range(2)),Iterator))Iterable、Iterator和Generator的关系
生成器对象即是可迭代对象,也是迭代器,因为生成器既可以用for循环求值,也可以通过next()求值,直到抛出StopIteration时无法继续生成新值
迭代器对象一定时可迭代对象,可迭代对象不一定为迭代器,因为迭代器、生成器、可迭代对象都可以用for循环迭代求值,只有生成器和迭代器可以被next()方法求值
相关文章推荐
- python生成器,可迭代对象,迭代器区别和联系
- python中生成器和迭代器以及可迭代对象的区别
- Python可迭代对象,迭代器,生成器的区别
- 可迭代对象,迭代器(生成器)区别
- 学习7: 列表生成式,生成器,迭代器,可迭代对象
- Python之列表生成式、生成器、可迭代对象与迭代器
- Python(迭代、三元表达式、列表生成、生成器、迭代器)
- 完全理解Python迭代对象、迭代器、生成器
- 完全理解 Python 迭代对象、迭代器、生成器
- python之迭代器、生成器、可迭代对象
- python的高级特性:切片,迭代,列表生成式,生成器,迭代器
- 流畅的python第十四章可迭代的对象,迭代器和生成器学习记录
- 【python】 可迭代对象、迭代器、生成器
- 迭代器、可迭代对象、生成器
- Python高级特性(切片,迭代,列表生成式,生成器,迭代器)
- 迭代器、迭代对象、闭包的应用、装饰器
- 完全理解Python迭代对象、迭代器、生成器
- python 生成器、列表/字典/集合解析式区别
- 迭代器、迭代对象、闭包的应用、装饰器
- 迭代器、可迭代对象与生成器