我们先考虑一个场景:

  有个情景需要循环输出1——10.

  这里给两种方法:

list1 = [1,2,3,4,5,6,7,8,9,10]
for i in list1:
print(i)
for i in range(1,11):
print(i)

两种方式输出结果一样,但是我们考虑一下,如果要求输出1——1000000呢?

第一种方式会导致list1里面真实放入1000000长度的数字,占用空间很大,明显不是明智之举,

再来看第二种方法,用到range帮助我们生成数据,在python3中range的本质就是一个生成器。

在python2中:range返回的是一个等差列表,比如[0,1,2,3,4,5,6,7,```````], 而xrange才是返回一个生成器对象. 即python2 range()==[```````````````````], python2 xrange()==python3 range()

具体对比查看:https://blog.csdn.net/humanking7/article/details/45950967

(一)这里写一个函数,在生成器函数的名称中加上gen 前缀或后缀,不过这不是必要的习惯:

 def gen_create_range(start,end):

     while start < end:
yield start
start += 1 for i in gen_create_range(1,5):
print(i)

 #output:

1

    2

    3

    4

这个函数没有return 但是可以有返回值,注意看里面有个yield关键字,这个函数和range()函数很像。

(二)什么是生成器:函数定义中包含yield关键字那么函数就变成了生成器

  概念:如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator   

  生成器表达式: 通列表解析语法,只不过把列表解析的[]换成()  

g= (x**2 for x in range(5))

print g

>>
<generator object <genexpr> at 0x0000000002771798> #如果、
L=[x**2 for x in range(5)] print L >>
[0, 1, 4, 9, 16]

  也就是说:创建L和g的区别仅在于最外层的[]和(),L是一个list,而g是一个generator

1).函数中只要出现了yield语句就会将其转变成一个生成器函数

  • 特别之处在于,yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator

  • 与普通函数不一样,生成器值会在迭代操作的时候才能运行.yiled可以把函数中断,保存状态和继续执行的能力

好比一个武打片里面的慢镜头回放,yield把函数里面你要保存的值中断并保存,你通过调用next()来回放

 

比如:

def countdown(n):
print('Starting to count from',n)
while n>0:
yield n
n-=1
print('done') c=countdown(3)
print(c)
>>
<generator object countdown at 0x0000000002821828>
#表示这是一个生成器

2).调用该generator时,首先要生成一个generator对象,然后用next()函数不断获得下一个返回值

比如:

c=countdown(3)

#run the first yield and emit a value

print(next(c))

>>

Starting to count from 3

3

#run the next yield

print(next(c))

>>

2

#run the next yield

print(next(c))

>>

1

#run the next yield

print(next(c))

>>

done

    print next(c)

StopIteration

深入解释:

你把yield想象成时间断点,运行一次next就回放一下,看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值

  • 第一次next()是打印了 print('Starting to count from',n),提取第一次的保存值是3

  • 第二次再运行next()是继续在while里面的断点接着走,所以没有打印print('Starting to count from',n), 而是直接提取第二次的保存值2

  • 第三次再运行next()是继续在while里面的断点接着走,所以直接输出1

  • 第四次再运行next()的时候,发现yield缓存的武打片慢镜头都已经放完了,所以输出done之后,报了个错StopIteration

3).生成器函数用for循环

for n in countdown(6):
  
  print(n) >> Starting to count from 6 6 5 4 3 2 1 done

 

正确的方法是使用for循环,因为generator也是可迭代对象

4yield 与 return相爱相杀

1).在一个生成器中,如果没有return,则默认执行到函数完毕时返回StopIteration

def gen1():
yield 100 g1=gen1()
print(next(g1))
>>100

第一次调用next(g1)时,会在执行完yield语句后挂起,所以此时程序并没有执行结束。

print(next(g1))
>>
Traceback (most recent call last):
File "C:/about_gen.py", line 71, in <module>
print(next(g1))
StopIteration

程序试图从yield语句的下一条语句开始执行,发现已经到了结尾,所以抛出StopIteration异常

 

2).如果遇到return,如果在执行过程中 return,则直接抛出 StopIteration 终止迭代

def gen2():
yield 200
return
yield 300 g2=gen2()
print(next(g2))
>>200
# 程序停留在执行完yield 200语句后的位置 print(next(g2))
>>
File "C:/about_gen.py", line 82, in <module>
print(next(g2))
StopIteration

程序发现下一条语句是return,所以抛出StopIteration异常,这样yield 'b'语句永远也不会执行

生成器这个概念一开始很难理解,有点古怪,但是时间久了才知道他的妙用

另外生成器函数是没有办法使用return来返回值

python中的生成器(一)的更多相关文章

  1. python中的生成器函数是如何工作的?

    以下内容基于python3.4 1. python中的普通函数是怎么运行的? 当一个python函数在执行时,它会在相应的python栈帧上运行,栈帧表示程序运行时函数调用栈中的某一帧.想要获得某个函 ...

  2. Python学习-39.Python中的生成器

    先回顾列表解释 lista = range(10) listb = [elem * elem for elem in lista] 那么listb就将会是0至9的二次方. 现在有这么一个需求,需要存储 ...

  3. python中的生成器(二)

    一. 剖析一下生成器对象 先看一个简单的例子,我们创建一个生成器函数,然后生成一个生成器对象 def gen(): print('start ..') for i in range(3): yield ...

  4. Python中的生成器与yield

    对于python中的yield有些疑惑,然后在StackOverflow上看到了一篇回答,所以搬运过来了,英文好的直接看原文吧. 可迭代对象 当你创建一个列表的时候,你可以一个接一个地读取其中的项.一 ...

  5. 聊聊Python中的生成器和迭代器

    Python中有两个重要的概念,生成器和迭代器,这里详细记录一下. 1. 生成器 什么是生成器呢? 通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包 ...

  6. python中的生成器(generator)总结

    1.实现generator的两种方式 python中的generator保存的是算法,真正需要计算出值的时候才会去往下计算出值.它是一种惰性计算(lazy evaluation). 要创建一个gene ...

  7. python学习之【第十三篇】:Python中的生成器

    1.为什么要有生成器? 在Python中,通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅 ...

  8. python中的生成器、迭代器、闭包、装饰器

    迭代器 迭代是访问集合元素的一种方式.迭代器是一个可以记住遍历的位置的对象.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退. 可迭代对象 以直接作用于 for ...

  9. python中的生成器和迭代器

    前言: 我们来了解一下什么是python中生成器.了解一下python生成器是什么,以及生成器在python编程之中能起到什么样的作用. 定义: 生成器和迭代器 通过列表生成式,我们可以直接创建一个列 ...

随机推荐

  1. EBS-BG&LE&OU

    SELECT DISTINCT hrl.country,                hroutl_bg.NAME            bg,                hroutl_bg.o ...

  2. 作业一:博客和Github简单练习

    (1)自我介绍 Hello everybody! 我叫纪杨阳,学号1413042002,网络工程141班. 本人没啥特殊的兴趣爱好,都是些平常得不能再平常的吃吃睡睡.要说感兴趣的,可能就是音乐和服饰还 ...

  3. [Postgres]Postgres复制表

    在需要把含有分表的总表备份的时候想到的笨办法,如果有什么更先进的办法万望告知. 比如TableOld是由TableOld1,TableOld2,TableOld3组合而成,现在需要对TableOld进 ...

  4. 学习python的第五天

    4.30自我总结 一复习 1.查看数据类型 #数值10的位置 print(di(10)) #数值10的样式 print(type(10)) 2.关于变量的一些补充 a=1 b=1 c=1 #a,b,c ...

  5. linux gitlab-ctl reconfigure报错问题修复 502

    Running handlers: There was an error running gitlab-ctl reconfigure: bash[migrate gitlab-rails datab ...

  6. WebBrowser控件支持WebSocket

    修改html页面,在Header标签中添加如下标签: <meta http-equiv="X-UA-Compatible"content="IE=edge" ...

  7. sqlserver排名函数

    在做开发的时候,排名函数是sqlserver经常用到的函数,在分页的时候需要用,分组的时候也要用,主要排名函数有row-number,rank(),dense-rank(),NTILE()接下来详细说 ...

  8. Enabling Remote Errors in SSRS

    January 18, 2011 By default the remote errors property in SQL Server Reporting Services is set to fa ...

  9. Android Activity 无法获取组件尺寸

    Activity 创建的时候,可能在 onCreate 的时刻,窗口 Window 对象的创建还未完成. 那么最合适的时机是什么呢?答案是:onWindowFocusChanged.这个方法在 Act ...

  10. Android Studio如何用真机调试

    1,在真机中设置USB调试模式打开,具体:“设置”->“应用程序”->“开发”->“USB调试”. 2,安装安卓的USB驱动,如果按照不好,那么去下载一个豌豆荚,它会帮你正确安装你的 ...