函数4—迭代器与生成器

基础概念
迭代器:

为什么: 提供了一种不依赖于索引的取值方式,如字典,集合,文件等没有索引的类型需要循环取出元素
迭代器是惰性计算,更节省内存,迭代器在内存中只是一个内存地址,一次只取一个值

缺点:永远无法获取迭代器的长度,使用不如列表索引取值灵活
一次性的,只能往后取值
可迭代的:对象本身有__iter__方法
i = iter(n) or i = n.__iter__() i 为n的迭代器
next(i) or i.__next__() 利用迭代器输出内容,一次输出一个


生成器:
定义: 函数中包含yield语句
将生成器函数(有yield)返回的g作为迭代器使用,这个g就是生成器, 每次next生成器,就执行一次函数
即 将整个函数作为迭代器
yield与return 的区别:
return只能执行一次函数就彻底结束,yield 能多次返回值
yield的作用:
把函数的返回值变成迭代器 ---------》生成器
将iter next函数封装到函数内部, 将函数变为一个迭代器对象(将函数变成了一个类似序列类型的对象)
多次输出函数运行结果
每次触发就运行一次函数,保存函数在暂停及继续下一次运行时的状态


协程函数 本质是一种生成器函数,函数中的yield由表达式所写 面向过程编程的主要形式
e.send() 与 next(e)的区别:
二者的共同之处是度可以让函数在上次暂停的位置继续运行
二者都可以返回yield后面的返回值
如果函数内yield是表达式形式,那么必须先next(e)
send在触发下一次next的时候会给上次的yield传值
所有的生成器函数都只能通过next send 和for循环来逐次运行函数,且生成器函数本身不会运行


迭代器 与生成器的相同:生成器是迭代器的一种,生成器具有迭代器全部的功能 惰性计算
不同:
迭代器只是每次返回一个已知序列的值
生成器保存了一个算法,比迭代器多了一个功能是边运行边计算,返回一个运算过的序列的值


迭代器---------->生成器---------->生成器的表达式应用:协程函数----------->面向过程的编程:利用了函数式编程的思想

l = ['a','b','c','d']
#while循环列表
i =0
while i < len(l):
print(l[i])
i += 1
# for 循环列表
for i in range(len(l)): #使用索引取出元素
print(l[i])

for i in l: #使用for自带的迭代器取出元素
print(i)

d = {'a':1,'b':2,'c':3}
#while 循环字典
g = d.__iter__() #迭代器g
print(type(g))
while True:
try: #捕捉异常
print(next(g)) #迭代器的方法__next__()
except StopIteration:
break

#for 循环字典

for i in g: #g已经是一个迭代器,但for循环中的自动转迭代器不会影响遍历字典
print(i)

for i in d: #for循环内包含了iter ,next ,和 自动捕捉异常的函数
print(i)

#while循环文件
while True:
try:
print(next(f))
except StopIteration:
break
#for循环文件
with open('a.txt') as f:
for line in f:
print(line.strip())

f = open('a.txt')
f.__iter__() #文件本身就是一个迭代器
print(f.__next__())

s = 'hello'
l = [1,2,3]
t = (1,2,3)
d = {'a':1}
s = {'a','b'}
f = open('a.txt')
# 查看可迭代对象
from collections import Iterable
s.__iter__()
print(isinstance(l,Iterable))
#查看迭代器对象
from collections import Iterator
f.__next__()
print(isinstance(l,Iterator))



#生成器
def test(): #生成器函数
print('one')
yield 1
print('two')
yield 2
print('three')
yield 3
print('four')
yield 4
print('five')
g = test() #返回一个生成器 同时也是一个迭代器,可以作为迭代器使用

g.__next__()
g.__next__()
g.__next__()
g.__next__()
#生成器的应用
def countdown(n):
print('start')
while n > 0:
yield n
n -= 1
print('done')
g = countdown(5)

# 生成器中迭代器的应用
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))

while True:
try:
print(next(g))
except StopIteration:
break

for i in g:
print(i)
#生成器有个迭代器的属性:惰性计算 如下函数 生成器可以一直运行,而且内存不会卡
def func():
n = 0
while True:
yield n
n += 1
g = func()
#print(next(f))
for i in g:
print(i)


print(isinstance((x for x in range(10)),Iterable))
#生成器应用:随时监听文件中的错误日志
#/usr/bin/env python
import time
def tail(file_path):
with open(file_path) as f:
f.seek(0,2)
while True:
line = f.readline()
if not line:
time.sleep(0.5)
continue
else:
#print(line,end='')
yield line
def grep(pattern,lines):
for line in lines:
if pattern in line:
yield line
g1=tail('/tmp/a.txt')
g2=grep('error',g1)
for i in g2:
print(i)

#生成器的表达式应用:协程函数
def eater(name):
print('%s start to eat food'%name)
food_list=[]
while True: #必须加while循环,为每次生成器发送的值创造循环条件
food = yield food_list
print('%s got %s to start eat'%(name,food))
food_list.append(food)
print('done')

e = eater('gangdan')

print(next(e))
print(e.send('baozi')) #生成器在向函数发送参数时,以元组的形式发送,所以发送多个参数时,要加上()表示元组
print(e.send('miantiao'))
print(e.send('mifan'))

#为生成器添加装饰器
def nextn(func):
def wrapper(*args,**kwargs):
res = func(*args,**kwargs)
next(res)
return res
return wrapper
@nextn
def eater(name):
print('%s start to eat food'%name)
food_list=[]
while True:
food = yield food_list
print('%s got %s to start eat'%(name,food))
food_list.append(food)
print('done')

e = eater('liuliu')
e.send('baozi')


#迭代器应用:实现功能 cat a,txt | grep apple
import time
def cat():
while True:
with open('a.txt') as f:
lines = f.readline()
if not lines:
time.sleep(1)
continue
else:
yield lines

def grep(pattern,lines):
for i in lines:
if pattern in i:
print(i)
exit()


g = cat()
grep('apple',g)

#生成器应用: 把下面的函数改成生成器的形式,执行生成器函数得到一个生成器g,然后每次g.send(url),
# 打印页面内容,利用g可以无限send
from urllib.request import urlopen
def opener(url):
while True:
print(urlopen(url).read())
url=yield
g = opener('http://www.baidu.com')
next(g)
g.send('http://www.360.com')


def get(url):
while True:
def index():
res = urlopen(url).read()
print(res)
index()
url = yield

g = get('http://www.baidu.com')
next(g)
g.send('http://www.360.com')
posted @ 2017-04-15 17:25  柳姑娘  阅读(196)  评论(0编辑  收藏  举报