列表生成式、生成器迭代器
列表生成式、生成器&迭代器
一、列表生成式(List Comprehensions)
1、案例——列表每个值加1
先有列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
,要求你把列表里的每个值加1,怎么实现?
方法一:
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] b = [] for i in a:b.append(i+1) a = b print(a)
此方法内存中会同时有两份列表,因此不适合处理大规模数据。
方法二:
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] for index,i in enumerate(a):a[index] +=1 print(a)
方法三:
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] a = map(lambda x:x+1, a) # <map object at 0x1018da5f8> print(a)
利用map方法根据提供的函数(lambda)对指定序列做映射。
方法四:
# 列表生成式:一行代码完成列表操作 a = [i+1 for i in range(10)]
2、列表生成式概念和用法
列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。
# 写列表生成式时,把要生成的元素x * x放到前面,后面跟for循环,就可以把list创建出来 >>> [x * x for x in range(1, 11)] [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]# for循环后面还可以加上if判断,这样我们就可以筛选出仅偶数的平方 >>> [x * x for x in range(1, 11) if x % 2 == 0] [4, 16, 36, 64, 100]# 用三元运算生成列表 >>> a = range(1,11) >>> a = [i if i < 5 else i*i for i in a] >>> a [1, 2, 3, 4, 25, 36, 49, 64, 81, 100]# 使用两层循环,可以生成全排列 >>> [m + n for m in 'ABC' for n in 'XYZ'] ['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']# 列表生成式也可以使用两个变量来生成list >>> d = {'x': 'A', 'y': 'B', 'z': 'C' } >>> [k + '=' + v for k, v in d.items()] ['x=A', 'y=B', 'z=C']# 字符串操作,都变为小写 >>> L = ['Hello', 'World', 'IBM', 'Apple'] >>> [s.lower() for s in L] ['hello', 'world', 'ibm', 'apple']
由此可以看到,通过列表生成式可以直接创建一个列表。列表创建在内存中,因此列表容量受到内存限制。特别是对一个元素量很大的列表,仅需访问前几个元素时,尤其浪费空间。
二、生成器(generator)
1、生成器定义
列表元素可以按照某种算法推算出来(有规律的数组),则可以在循环的过程中不断推算出后续的元素。这种方式就不必创建完整的list,可以节省大量的空间。
python中,这种一边循环一边计算的机制,称为生成器:generator。
2、生成器创建方法一:将列表生成式的‘[]’改为‘()’
创建列表生成式和生成器的区别,仅仅是最外层的[]和()。
如果要打印出生成器的元素,可以通过nex()函数获取generator的下一个返回值。
# 生成器保存的是公式,取一次创建一次,只能往前不能后退 >>> a2 = (i for i in range(1000)) >>> a2 <generator object <genexpr> at 0x103761a98> >>> next(a2) 0 >>> next(a2) 1#生成器走完时,会报错:StopIteration >>> a3 = (i for i in range(5)) # 限制5个 >>> a3 <generator object <genexpr> at 0x103761e08> >>> next(a3) 0 >>> next(a3) 1 >>> next(a3) 2 >>> next(a3) 3 >>> next(a3) 4 >>> next(a3) Traceback (most recent call last):File "<input>", line 1, in <module> StopIteration
生成器保存的是算法,每次调用next(g)就计算出g的下一个元素的值,直到计算出最后一个元素,没有更多的元素时,抛出StopIteration的错误。
创建生成器后,很少会调用next(),一般是通过for循环来迭代。
a3 = (i for i in range(5)) for i in a3: # 使用for循环来迭代生成器,不会出现StopIteration报错,直接结束。print(i) ''' 0 1 2 3 4 '''a2 = (i for i in range(3)) while True: # while循环不适用next(a2) # 报StopIteration错误
3、生成器创建方法二:一个函数定义中包含yield关键字,函数为生成器(generator)
例如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数均可由前两个数相加得到:1, 1, 2, 3, 5, 8, 13, 21, 34,....
列表生成式写不出斐波拉契数列,但是函数却可以轻松打印:
# 用函数来写生成器,以斐波那契数列为例 # 重点是赋值语句:a,b = b,a+b def fib(max): n, a, b = 0, 0, 1while n < max:print(b) # 每次打印ba, b = b, a + b # 0,1——>1,1——>1,2——>2,3n = n + 1 # n用来计数,每次自加1return 'done'fib(10)
赋值语句:a, b = b , a + b
相当于:t = (b, a + b) a = t[0] b = t[1] t是一个tuple
fib
函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。
>>> def fib_g(max): ... n, a, b = 0, 0, 1 ... while n < max: ... print('before yield') ... yield b # yield 把函数的执行过程冻结在这一步,并且把b的值返回给外面的next() ... print(b) ... a, b = b, a+b ... n = n + 1 ... return 'done' ... >>> f = fib_g(15) # 将函数转换为生成器,有了yeild后,函数名(参数)根本不执行 >>> next(f) before yield 1 >>> next(f) 1 before yield 1 >>> next(f) 1 before yield 2 >>> next(f) 2 before yield 3 >>> next(f) 3 before yield 5
这种生成器和函数相似,但与函数的执行流程不同:
函数是顺序执行,遇到return语句或最后一行函数语句就返回。
函数转化为生成器后,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
def fib_g(max):n, a, b = 0, 0, 1while n < max:# print('before yield')yield b # yield 把函数的执行过程冻结在这一步,并且把b的值返回给外面的next()# print(b)a, b = b, a+bn = n + 1return 'done' # 生成器使用意义:可以将函数执行中的状态、数据返回到外部来 data = fib_g(10) print(data)print(data.__next__()) print(data.__next__()) print("干点别的事") print(data.__next__()) print(data.__next__()) print(data.__next__()) print(data.__next__())""" <generator object fib_g at 0x1014670f8> 1 1 干点别的事 2 3 5 8"""
在上例中,循环过程中不断调用yield,就会不断中断。而且需要设置循环退出条件,否则会产生无限数列。
将函数改写为生成器后,通常不会用next()来获取下一个值,而是使用for循环来迭代。
def fib_g(max):n, a, b = 0, 0, 1while n < max:yield b # yield 把函数的执行过程冻结在这一步,并且把b的值返回给外面的next()a, b = b, a+bn = n + 1return 'done'for n in fib_g(6):print(n)""" 1 1 2 3 5 8 """
for循环调用生成器,拿不到生成器的return语句的返回值,要拿到返回值,必须捕获StopIteration错误。
def fib_g(max):n, a, b = 0, 0, 1while n < max:yield b # yield 把函数的执行过程冻结在这一步,并且把b的值返回给外面的next()a, b = b, a+bn = n + 1return 'done'g = fib_g(6) while True:try:x = next(g)print('g', x)except StopIteration as e:print('Generator return value:', e.value)break""" g 1 g 1 g 2 g 3 g 5 g 8 Generator return value: done """
4、生成器send方法
send方法作用:
1、唤醒并继续执行 (next方法只有这个功能)
2、发送一个信息到生成器内部
def range2(n):count = 0while count < n:print('count', count)count += 1sign = yield countif sign == 'stop':breakprint("---sign", sign)return 3333 new_range = range2(3) # 0,1,2 n1 = next(new_range) print(new_range) new_range.send("stop") # 生成器不再执行后两步直接终止""" count 0 <generator object range2 at 0x10244c0f8> Traceback (most recent call last):File "/Users/.../函数生成器2.py", line 20, in <module>new_range.send("stop") StopIteration: 3333 """
如下所示为生成器与外部交互:
def run():count = 0while True:n = yield countprint("--", n, count)count += 1g =run()g.__next__() g.send("alex") g.send("egon") g.send("jack") """ -- alex 0 -- egon 1 -- jack 2 """
5、通过yield实现单线程情况下实现并发运算的效果
#_*_coding:utf-8_*_ __author__ = 'Alex Li'import time def consumer(name):print("%s 准备吃包子啦!" %name)while True:baozi = yieldprint("包子[%s]来了,被[%s]吃了!" %(baozi,name))def producer(name):c = consumer('A')c2 = consumer('B')c.__next__()c2.__next__()print("老子开始准备做包子啦!")for i in range(10):time.sleep(1)print("做了2个包子!")c.send(i)c2.send(i)producer("alex")通过生成器实现协程并行运算
三、生成器总结
1、生成器的创建方式
1.列表 列表生成式
2.函数 函数生成器 yield
2、yield 对比 return
return返回并中止function
yield返回函数,并冻结当前的执行过程
函数有了yield之后
(1)函数名加()就变成了一个生成器
(2)return在生成器里,代表生成器的中止,直接报错
3、next:唤醒生成器并继续执行
next唤醒冻结的函数执行过程,继续执行,直到遇到下一个yield
4、send("stop"):
1.唤醒并继续执行
2.发送一个信息到生成器内部
5、python2和python3中range()方法对比
在Python2中:
range = list
>>> range(10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
xrange = 生成器
>>> a = xrange(10) >>> type(a) <type 'xrange'> >>> for i in a: ... print i ... 0 1 2 3 4 5 6 7 8 9
在Python3中:
range = genetator
>>> range(10) # range(0,10) 生成这个公式没有正式创建 range(0, 10) >>> type(range(10)) <class 'range'>
xrange :python3中已取消该方法
四、可迭代对象(Iterable)和迭代器(Iterator)
1、什么是可迭代对象?什么是迭代器?
可直接作用于for循环的数据类型有一下几种:
一、集合数据类型,如:list、tuple、dict、set、str等;
二、generator,包括生成器表达式(geneator expression)和生成器函数(generator function)两组构建方式。
上述这些可以直接作用于for循环的对象统称为可迭代对象(Iterable)。可以使用isinstance()判断一个对象是否是Iterable对象。
from collections import Iterable # 可迭代类型 # 使用isinstance()判断一个对象是否是可迭代对象 isinstance('abc', Iterable) isinstance({}, Iterable) isinstance((x for x in range(10)), Iterable)isinstance(100, Iterable) # 返回False
迭代器定义:可以被next()函数调用并不断返回下一个值得对象称为迭代器(Iterator)。
2、可迭代对象与迭代器的关系
生成器是迭代器的一种:
1、生成器都是迭代器对象,但list\dict\str虽然是可迭代对象,但不是迭代器。
2、把list\dict\str等可迭代对象变成迭代器可以使用iter()函数
>>> from collections import Iterator >>> isinstance('abc', Iterator) False >>> a = iter('abc') >>> a <str_iterator object at 0x10c584b38> >>> a.__next__() 'a' >>> isinstance(iter([]), Iterator) True >>> isinstance(iter('abc'), Iterator) True
3、为什么list
、dict
、str
等数据类型不是Iterator
?
这是因为Python的Iterator
对象表示的是一个数据流,Iterator对象可以被next()
函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration
错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()
函数实现按需计算下一个数据,所以Iterator
的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator
甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
4、总结
凡是可作用于for
循环的对象都是Iterable
类型;
凡是可作用于next()
函数的对象都是Iterator
类型,它们表示一个惰性计算的序列;
集合数据类型如list
、dict
、str
等是Iterable
但不是Iterator
,不过可以通过iter()
函数获得一个Iterator
对象。
Python的for
循环本质上就是通过不断调用next()
函数实现的。
for x in [1, 2, 4, 5]:pass# 完全等价于 # 获得Iterataor对象 it = iter([1, 2, 3, 4, 5]) # 循环 while True:try:# 获得下一个值:x = next(it)except StopIteration:# 遇到StopIteration就退出循环break
列表生成式、生成器迭代器相关推荐
- python从random生成列表_Python 学习DAY 17 列表生成式,生成器,迭代器,time模块,random模块...
********************************************列表生成式****************** a=[x for x in range(10)] [0, ...
- python之路-列表生成式、迭代器、生成器、装饰器
1.列表生成式,迭代器&生成器 列表生成式 我现在有个需求,看列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],我要求你把列表里的每个值加1. 普通版 a = [0,1,2,3 ...
- python列表生成器语法_Python 列表生成式\生成器
Python 列表生成式+生成器 一.列表生成式 1.什么是列表生成器 一种可以便捷地生成列表的表达式,有时候可以替换list.append(变量) 2.需求. 如何将列表中的每个数据都加1 列表:d ...
- 列表生成式,生成器表达式,模块的使用
三元表达式 无论条件成立与否都要返回一个值, 用于简化仅有一个判断的函数(或代码块)递归 递归有循环调用的次数限制,调用函数时,函数相关数据要入栈,而栈区是有限的 二分查找法匿名函数 仅能在定义时使用 ...
- python 列表生成式_深度好文:Python之列表生成式、生成器、可迭代对象与迭代器(一)...
作者:云游道士 原文:https://www.cnblogs.com/yyds/p/6281453.html 本节内容 语法糖的概念 列表生成式 生成器(Generator) 可迭代对象(Iterab ...
- Python高级特性:切片、迭代、列表生成式、生成器与迭代器
点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 接着廖雪峰老师的学习教程,小编要开始加快推进Python的学习进程 ...
- Python高级特性(切片,迭代,列表生成式,生成器,迭代器)
掌握了Python的数据类型.语句和函数,基本上就可以编写出很多有用的程序了. 比如构造一个1, 3, 5, 7, ..., 99的列表,可以通过循环实现: L = [] n = 1 while n ...
- python迭代器和生成器(3元运算,列表生成式,生成器表达式,生成器函数)
1.1迭代器 什么是迭代器: 迭代器是一个可以记住遍历的位置对象 迭代器对象从集合的第一个元素元素开始访问,直到所有元素被访问完结束,迭代器只能往前不会后退. 迭代器有两个基本方法:iter ,nex ...
- 列表生成式、生成器、迭代器
一句话概念 列表生成式--可以直接在列表里进行运算 生成器--一边循环一边计算的机制,称为生成器:generator(就是生成一个不运行的函数或者列表,即数据流) 第二句:生成器与列表的区别--生成器 ...
- 【Python基础】Python高级特性:切片、迭代、列表生成式、生成器与迭代器
接着廖雪峰老师的学习教程,小编要开始加快推进Python的学习进程了.今天的笔记内容是Python高级特性,其中包括快速访问对象类型元素的切片.循环中的迭代意义.方便的列表生成式操作以及生成器和迭代器 ...
最新文章
- Science:Knight组发表尸体降解过程中的微生物组
- 高才生的好帮手-Word2010(3)
- oracle中的decode的使用
- 石墨烯可提高热成像质量 提高安检准确性
- Discuz验证码识别(上线篇)-写给程序员的TensorFlow教程
- C语言中兴面试编程题,中兴一套笔试题及部分答案
- 使用PHPCS+GIT钩子保障团队开发中代码风格一致性实践
- 【数据结构】量子危机
- scp从另一台服务器下载或者上传文件
- MRI_Made_Easy 磁共振成像原理-物理基础5
- Model-Free Adaptive Predictive Control
- 第四章 SQL语法分类
- V831基础-摄像头使用
- 我对移动端架构的思考
- iOS XCode支持低系统版本
- 如何在visio中画出矩阵
- xgboost原理(无推导就轻易理解)
- 企业物流营销组合模式探讨 (zt)
- 【B端·BI系统实战分析】BI系统概述
- 51nod3107 小明爱宝石
热门文章
- 锂电池参数含义与供电时间计算
- Ubuntu18.04设置动态ip详细步骤(可视化)
- dotnet NPOI 将word文件转为pdf的代码
- cesium 开发记录报错:DeveloperError: Appearance/Geometry mismatch.
- python code自留地(1)
- 学习记录,利用Redis的(sorted set)做每周热评的功能
- Android平台签名证书(.keystore)生成指南-保姆级
- python库之—psycopg2
- S7-300 400 PLC 系统软件冗余调试的常见问题
- 测试高考体育成绩的软件,高考体育测试提前准备!考生最关心的评分标准等问题解答...