函数—生成器篇

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 动态库加载路径修改

    1.在 /etc/ld.so.conf 文件中添加搜索路径,重启或者 ldconfig 生效: 2.在 /etc/ld.so.conf.d 目录下添加 *.conf 文件,其中可以添加搜索路径,重启获 ...

  2. ceph 移除 osd

    1:从crush中移除节点ceph osd crush remove osd.0 2:删除节点ceph osd rm osd.0 3:删除节点认证(不删除编号会占住)ceph auth del osd ...

  3. Delphi XE2 新增 System.Zip 单元,压缩和解压缩文件

    Delphi XE2 新增 System.Zip 单元, 可用一句话压缩整个文件夹了 单元内主要就是 TZipFile 类, 最方便使用的是它的类方法: TZipFile.ExtractZipFile ...

  4. linux网络流量实时监控工具之iptraf 【个人比较喜欢用的流量监控软件】

    linux网络流量实时监控工具之iptraf IPTraf是一个网络监控工具,功能比nload更强大,可以监控所有的流量,IP流量,按协议分的流量,还可以设置过滤器等,如下图 对监控网络来说,这个更适 ...

  5. “全栈2019”Java第九十三章:内部类应用场景(迭代器设计模式)

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  6. leecode刷题(17)-- 实现StrStr

    leecode刷题(17)-- 实现StrStr 实现StrStr 描述: 实现 strStr() 函数. 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串 ...

  7. [arc079f] Namori Grundy 分类讨论

    Description 给给全有一个NN个点NN条边的有向图,点的的编号从11到NN 给给全的图有NN条边,形如:(p1,1),(p2,2),...,(pN,N)(p1,1),(p2,2),...,( ...

  8. Wannafly挑战赛29题解

    这套题目非常有意思啊23333--话说为啥没有上条先生的呢-- 传送门 \(A\) 御坂美琴 蠢了--首先先判总共加起来等不等于\(n\),不是的话就不行 然后dfs记录\(n\)不断分下去能分成哪些 ...

  9. SpringData JPA复合主键

    上一篇博客简单介绍了SpringData JPA实现简单的CRUD,分页与多条件的排序,那里的主键类型是Long,有时我们会遇到主键不是一个的,复合主键,经过调研如下.确定一个人,不能只根据他的姓名来 ...

  10. Android实用代码片段

    有时候,需要一些小的功能,找到以后,就把它贴到了博客下面,作为留言,查找起来很不方便,所以就整理一下,方便自己和他人. 一.  获取系统版本号: 1 PackageInfo info = this.g ...