函数—生成器篇

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中的惰性求值》

最新文章

  1. FZU 1914 单调队列
  2. nsurl 测试ATS
  3. 如何取消win10电脑自动更新
  4. SharePoint 2013 删除母版页报错“This file may not be moved, deleted, renamed, or otherwise edited”
  5. 20145120 《Java程序设计》第8周学习总结
  6. python sqlalchemy-migrate 使用方法
  7. Swift - 使用UISearchController实现带搜索栏的表格
  8. JAVA基础----持续更新
  9. 模板引擎(smarty)知识点总结
  10. Microsoft dynamic 批量更新
  11. Python脚本自动提取和替换代码中的中文
  12. 论文笔记系列-iCaRL: Incremental Classifier and Representation Learning
  13. [译]通往 Java 函数式编程的捷径
  14. Vim on Mac Terminal
  15. 我的小游戏上线海外AppStore完整流程心得
  16. JS设计模式——8.桥接模式
  17. 转 CAS实现SSO单点登录原理
  18. hdu 1690 Bus System (最短路径)
  19. 洛谷——P1748 H数
  20. 【Floyd】【Dilworth定理】【最小路径覆盖】【匈牙利算法】bzoj1143 [CTSC2008]祭祀river

热门文章

  1. 瞄一眼,带你走进SparkSQL的世界
  2. Linux 常用命令大放送
  3. Exp3 免杀原理与实践 20164323段钊阳
  4. CAS客户端整合(二) Zabbix
  5. LOJ#2070. 「SDOI2016」平凡的骰子(计算几何)
  6. 洛谷P5284 [十二省联考2019]字符串问题(SAM+倍增+最长路)
  7. AngularJS入门讲解1:angular基本概念
  8. linux互传文件nc命令
  9. 架构师养成记--21.netty编码解码
  10. JQ 文件上传