函数—生成器篇

1. 认识和区分可迭代or生成器

1.1 可迭代对象

当你建立了一个列表,你可以逐项地读取这个列表,这叫做一个可迭代对象

当你使用一个列表生成式来建立一个列表的时候,就建立了一个可迭代的对象

所有可以使用  for..in..语法的叫做一个迭代器:例如列表,字符串,文件……

经常使用它们是因为我们可以如愿的读取其中的元素,但是你把所有的值都存储到了内存中,如果你有大量数据的话这个方式并不是你想要的

mylist=[ x*x for x in range(3) ]
for i in mylist:
print(i) for i in mylist:
print(i)
0
1
4
0
1

1.2 生成器

生成器是可以迭代的,但是你只可以读取它一次,因为它并不把所有的值放在内存中,它是实时地生成数据

mygenerator=( x*x for x in range(3) )
for i in mygenerator:
print(i) for i in mygenerator:
print(i) 0
1
4

2. 理解生成器 & yield

2.1 生成器是惰性求值的

惰性求值也叫延迟求值,顾名思义就是表达式不会在它被绑定到变量之后就立即求值,而是等用到时再求值。

延迟求值的一个好处是能够建立可计算的无限列表而没有妨碍计算的无限循环或大小问题。

考虑到yield的特性:可在减少内存占用、避免使用递归等场景时选择yield

2.2  生成器函数的执行流程

# yield关键字的作用是把一个函数变成一个generator,称为生成器函数。
# 生成器函数的返回值是生成器

* 生成器函数执行的时候,不会执行函数体
* 当next生成器的时候, 当前代码执行到之后的第一个yield,会弹出值,并且暂停函数
* 当再次next生成器的时候,从上次暂停处开始往下执行
* 当没有多余的yield的时候,会抛出StopIteration异常,异常的value是函数的返回值

通过以下例子来理解generator执行流程:

def gen(x):
if x!=0:
yield x mygenerator=gen(3) print(mygenerator) #当我们调用这个函数时,我们发现函数内部的代码并不立马执行,而只是返回了一个生成器对象
#<generator object gen at 0x7f63ee065888> for i in mygenerator: #当你使用for进行迭代时,函数内的代码才执行
print(i)
#3 print(next(mygenerator)) #或者使用next()
#3
def gen(max):         # def gen():
a,b=1,1 # do something (a)
while a<max:
yield a # yield a # (b)
a,b=b,a+b # do something (c) for n in gen(15): # for n in gen():
print(n) # do something with n (d)

def dedupe(items):
seen = set()
for item in items:
if item not in seen:
yield item
seen.add(item) a = [1, 5, 2, 1, 9, 1, 5, 10]
for n in dedupe(a):
print(n)
1
5
2
9
10 执行大致过程(个人理解,有误请指正):
        seen=set( )    生成器环境初始化
|
dedupe内的for循环
|
调用yield item=1
|
print 1
|
add 1
|
dedupe内的for循环
|
调用yield item=5
|
print 5
|
add 5
|
dedupe内的for循环
|
调用yield item=2
|
print 2
|
add 2
|
dedupe内的for循环('1'已经在items里所以不执行循环)
|
dedupe内的for循环
|
调用yield item=9
|
......
def gen():
print('a')
yield 1
print('b')
yield 2
return 3 g=gen() print(g)
#<generator object gen at 0x7f144845a308> print(next(g))
#a
#1 print(next(g))
#b
#2 print(next(g))
#StopIteration: 3

3. 生成器作用场景

3.1  计数器的例子

# version-1
def counter():
x=0
while True:
x+=1
yield x def inc(x):
return next(x) # version-2
def counter():
x=0
while True:
x+=1
yield x def inc():
c=counter()
return lambda :next(c) # version-3
def make_inc():
def counter():
x=0
while True:
x+=1
yield x
c=counter()
return lambda :next(c)
## 为什么这里不直接 return next(c) ##
def make_inc():
def counter():
x=0
while True:
x+=1
yield x
c=counter()
return lambda :next(c)
# return lambda:next(c)的运行结果
incr=make_inc()
print(id(incr())) #取1
#8939648
print(id(incr())) #取2
#8939680 def make_inc():
def counter():
x=0
while True:
x+=1
yield x
c=counter()
return next(c)
# return next(c)的运行结果
print(id(make_inc())) #取1
#8939648
print(id(make_inc())) #取1
#8939648

3.2  解决递归问题 — 生成斐波那契数列的例子

def fib(max):
n,a,b=0,0,1
while n<max:
yield b
a,b=b,a+b
n+=1 for n in fib(5):
print(n) 1
1
2
3
5

3.3  协程 —— 生成器的高级用法

进程、线程 ——在内核态调度的
协程 ——在用户态调度(即用户自己写调度器)
——运行在一个线程之内,所以也被叫做轻量线程
——非抢占式调度
调度 ——简单的说就是由调度器来决定哪段代码占用cpu时间 协程在python3已经进入标准库了 ——asyncio
python3.5 中加入了 asyn、 await延伸支持

参考文章

《Python yield使用浅析-廖雪峰(含通过yield实现文件读取的方法)》

《[译]python关键字yield的解释(stackoverflow)》

《python中的惰性求值》

[PY3]——函数——生成器(yield关键字)的更多相关文章

  1. (转) Python Generators(生成器)——yield关键字

    http://blog.csdn.net/scelong/article/details/6969276 生成器是这样一个函数,它记住上一次返回时在函数体中的位置.对生成器函数的第二次(或第 n 次) ...

  2. 理解 ES6 语法中 yield 关键字的返回值

    在 ES6 中新增了生成器函数的语法,本文解释了生成器函数内 yield 关键字的返回值. 描述 根据语法规范,yield 关键字用来暂停和继续执行一个生成器函数.当外部调用生成器的 next() 方 ...

  3. PHP性能优化利器:生成器 yield理解

    如果是做Python或者其他语言的小伙伴,对于生成器应该不陌生.但很多PHP开发者或许都不知道生成器这个功能,可能是因为生成器是PHP 5.5.0才引入的功能,也可以是生成器作用不是很明显.但是,生成 ...

  4. Python:笔记(7)——yield关键字

    Python:笔记(7)——yield关键字 yield与生成器 所谓生成器是一个函数,它可以生成一个值的序列,以便在迭代中使用.函数使用yield关键字可以定义生成器对象. 一个例子 我们调用该函数 ...

  5. PHP 生成器 yield理解

    如果是做Python或者其他语言的小伙伴,对于生成器应该不陌生.但很多PHP开发者或许都不知道生成器这个功能,可能是因为生成器是PHP 5.5.0才引入的功能,也可以是生成器作用不是很明显.但是,生成 ...

  6. py3.0第四天 函数,生成器迭代器等

    1.列表生成式,迭代器&生成器 孩子,我现在有个需求,看列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],我要求你把列表里的每个值加1,你怎么实现?你可能会想到2种方式 > ...

  7. ES6学习笔记<三> 生成器函数与yield

    为什么要把这个内容拿出来单独做一篇学习笔记? 生成器函数比较重要,相对不是很容易理解,单独做一篇笔记详细聊一聊生成器函数. 标题为什么是生成器函数与yield? 生成器函数类似其他服务器端语音中的接口 ...

  8. Python:容器、迭代对象、迭代器、生成器及yield关键字

            在了解Python的数据结构时,容器(container).可迭代对象(iterable).迭代器(iterator).生成器(generator).列表/集合/字典推导式(list, ...

  9. day4 内置函数 迭代器&生成器 yield总结 三元运算 闭包

    内置函数: 内置函数 # abs()返回一个数字的绝对值.如果给出复数,返回值就是该复数的模. b = -100 print(b) print(abs(b)) # all() 所有为真才为真,只要有一 ...

随机推荐

  1. Linux 下 Memcached 缓存服务器安装配置

    Linux 下 Memcached 缓存服务器安装配置 [日期:2011-08-06] 来源:Linux社区  作者:Linux [字体:大 中 小]   [安装Memcache服务器端]我目前的平台 ...

  2. 在jquery中怎么使用css类名和id来获取元素?

    在jquery中,你可以很容易的使用CSS类名和id类获取元素. 例如: 1.ID:#id $('#idA')——选择id为idA的所有元素,不管元素的标签名如何. $('div#idA')——选择i ...

  3. .net core redis使用

    整理下.net core的redis使用  可以分布式 Nuget安装 StackExchange.Redis using System; using System.Collections.Gener ...

  4. JavaSe 之三目运算符应用

    刚学习Java基本知识,对于三目运算符的应用,尝试了做出求某年份中月份的天数. /*自己随意定义一个年份和月份,使用三目运算符 取得当前月份具体天数.并且输出在控制台. 注意哦:大月31天,小月30天 ...

  5. C# PowerPoint操作的基本用法。

    代码using System;using System.Collections.Generic;using System.Linq;using System.Text;using OFFICECORE ...

  6. Oracle数据库exp和imp方式导数据

    这里导入导出路径都在D盘下,默认文件名为:example.dmpexp方式导出数据相关参数项如下: 关键字  说明  默认USERID                     用户名/口令FULL   ...

  7. Java io流完成复制粘贴功能

    JAVA 中io字节输入输出流 完成复制粘贴功能: public static void main(String[] args) throws Exception{        // 创建输入流要读 ...

  8. clickonce联机模式

    发布时选择该程序只能联机使用,这样本地就不会进行安装. 参考地址:https://blog.csdn.net/dqs78833488/article/details/52513948

  9. 在IDEA中 SFTP 进行发布操作

    1, 2, 3, 4, 成功了 补充:] 也可以使用手动写配置文件的方式来的

  10. 用Yeoman构建AngularJS项目

    转至https://yq.aliyun.com/articles/25578 Yeoman 介绍 Yeoman 是 Google 的团队和外部贡献者团队合作开发的,他的目标是通过 Grunt(一个用于 ...