def average():
count=0
toatal=0
average=0
while True:
value=yield average
toatal+=value
count+=1
average=toatal/count
g=average()
print(g.__next__()) #激活了生成器,调用函数后 从头开始到 返回average 返回yield后面的average,为0
print(g.send(10)) #把10传递给yield前的value,继续执行后面的代码,value = 10 total= 10+0 count =1+0 average= 10/1 = 10
print(g.send(20)) #把20传递给yield前的value,继续执行后面的代码,value = 20 total= 10+20 count =1+1 average= 30/2 =15
print(g.send(30)) #把30传递给yield前的value,继续执行后面的代码,value = 30 total= 30+30 count =1+1+1 average= 90/3 =30
print(g.send(40))
print(g.send(50))
一、迭代器(dir()可以查函数具有什么键的功能)
1、可迭代的——iterable(字符串、列表、元组、字典、集合都可以被for循环,说明他们都是可迭代的。)
可以被for循环的都是可迭代的,要想可迭代,内部必须有一个__iter__方法。
(1)判断是否可迭代的方法:
from collections import Iterable
print(isinstance('aaa',Iterable) #输出结果:True
print(isinstance(123,Iterable) #输出结果:False
print(isinstance([1,2,3],Iterable) #输出结果:True
(2)可迭代协议
包含‘__iter__'方法的数据类型就是可迭代的。输出数据类型所有方法的方式如下:
#实例:求出两个不同数据类型的方法的不同 difference=set(dir([1,2,3]))-set(dir(123)) #dir()方法以列表形式列出数据的所有的方法 print(diffenrence)
2、迭代器——iterator
(1)判断迭代器的方法(迭代器 : __iter__ 和__next__)
from collection import Iterator iterator_lst=[1,2,3].__iter__() print(isinstance(itertor_lst,Iterator) #输出结果为:True print(isinstance([1,2,3],Iterator) #输出结果为:False
print('__next__' in dir([1,2,3,4])) # False
(2)迭代器协议
迭代器中有'__next__'和'__iter__'方法
(3)常见迭代器
a.先天的:文件句柄;b后天的:从可迭代对象转变,格式为:“可迭代对象.__iter__()”
(4)迭代器取值
lst_iterator=[1,2,3].__iter__() 先有iter print(lst_iterator.__next__()) 才能取值 #输出结果为:1 print(lst_iterator.__next__()) #输出结果为:2 print(lst_iterator.__next__()) #输出结果为:3 #超过迭代器中的内容就会报错:stopIterator
(5)优点(迭代器是个好东西)
3、二者的区别
(1)可迭代对象包含迭代器;(2)迭代器=可迭代对象.__iter__();(3)可以对可迭代对象和迭代器进行循环
二、生成器
1、定义:生成器就是迭代器,生成器是我们自己写出来的
2、生成器函数:带有关键字yield/yield from的函数就称为生成器函数
(1)生成器函数在执行时候只返回一个生成器,不执行生成器函数中的内容
(2)从生成器中取值
a.生成器.__next__():生成器函数中有几个yield,就可以取几次
def generator():
print(123)
yield 'aaa'
print(456)
yield 'bbb'
g=generator()
print(g.__next__()) # 123 aaa
print(g.__next__()) # 456 bbb
def list():
print(123)
yield 'aaa'
print(456)
yield 'bbb'
print(list().__next__()) # 123 aaa
print(list().__next__()) # 123 aaa
注意:前者为创建一个生成器,后者为每次重新创建一个生成器
b、for 循环取值
def func():
print(123)
yield 'aaa'
print(456)
yield 'bbb'
g=func()
for i in g:
print(i)
123
aaa
456
bbb
l = [1,2,3,4,5]
l_iter = l.__iter__() 定义
while True:
try:
print(l_iter.__next__())
except StopIteration: # 异常处理机制
break
实例、
def cloth():
for i in range(10000):
yield '衣服%s'%i
g = cloth()
for i in range(50):
print(g.__next__())
for i in range(50):
print(g.__next__())
list(生成器函数) 返回一个列表,里面装着生成器中的所有内容
def generator():
yield 'aaa'
yield 'bbb'
g=generator()
print(list(g)) # [aaa,bbb]
实例
1、监听器例子
监听器
def tail():
f = open('文件','r',encoding='utf-8')
f.seek(0,2) # 光标移至最后
while True:
line = f.readline()
if line:
yield line
import time
time.sleep(0.1)
g = tail()
for i in g:
print(i.strip())
生成器监听文件输入的例子
2、计算移动平均值
def averger():
total = 0.0
count = 0
average = None
while True:
term = yield average
total += term
count += 1
average = total/count
g_avg = averger()
next(g_avg)
print(g_avg.send(10))
print(g_avg.send(100))
print(g_avg.send(20))
print(g_avg.send(30))
三、重要会
def g_func():
print('aaaaa') # aaaaa
yield 1 # 返回值 每次只占用一次内存,用完就没了
print('bbbbb') #bbbbb
yield 2 # 返回值
yield 3 # 返回值
# return [1,2,3] #直接return 是列表,当列表数大的时候会比较占用内存
# for i in range(20000): #当数量较大时,生成器函数可以这样写、
# yield i
g = g_func()
# for i in g:
# print(i)
print(g.__next__())
print(g.__next__())
print(g.__next__())
def cloth(): for i in range(10000): yield '衣服%s'%i g = cloth() for i in range(50): print(g.__next__()) for i in range(50): print(g.__next__())
一、生成器中的send用法
send可以把一个值作为信号量传递到生成器函数中,然后和__next__方法一样获取生成器中的值;在生成器执行伊始,只能先使用__next__;二者都是终于yield,而send需要始于一个未被返还的yield处,否则传递的数值将无法被接收。
1、求重复累加平均实例
def average():
count=0
toatal=0
average=0
while True:
value=yield average
toatal+=value
count+=1
average=toatal/count
g=average()
print(g.__next__()) #激活了生成器,返回yield后面的average,为0
print(g.send(10)) #把10传递给yield前的value,继续执行后面的代码,终于yield后面的average,返回10
print(g.send(20)) #把20传递给yield前的value,继续执行后面的代码,终于yield后面的average,返回15
print(g.send(30)) #..........
print(g.send(40))
print(g.send(50))
2、用send传值失败实例
def func():
print(1)
yield 2
print(3)
value = yield 4
print(5)
yield value
g = func()
print(g.__next__()) #打印出1和返回2,然后在第一个yield处停止等待
print(g.send(88)) #由于第一个yield处没有未被返回的值,故send传值失败,打印出3和返回4,在第二个yield处停止等待
print(g.__next__()) #value无值传入,打印出5后在第3个yield处返回none
3、用next激活生成器计算累加平均值
def init(func): #在调用被装饰生成器函数的时候首先用next激活生成器
def inner(*args,**kwargs):
g=func(*args,**kwargs)
next(g)
return g
return inner
@init
def average():
mount=0
total=0
average=0
while True:
value=yield average
total+=value
average=total/mount
g_avg=average()
# next(g_avg) 在装饰器中执行了next方法
print(g_avg.send(10))
print(g_avg.send(20))
print(g_avg.send(30))
二、列表表达式和生成器表达式
1、列表表达式
简化代码,返回的必须是一个列表
#普通代码
result=[]
for i in [1,2,3]
result.append[i*i]
print(result)
#列表表达式
print([i*i for i in [1,2,3]])
(1)30内能被3整除的数的实例
print([i for i in range(1,31) if i%3==0])
(2)找到嵌套列表中有两个‘e’的名字
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'], ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
print([for list in names for name in list if name.count('e')==2])
2、生成器表达式
把列表解析的[]换成()得到的就是生成器表达式;列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存
laomuji=('鸡蛋%s' %i for i in range(10)) #生成器表达式
print(laomuji) #返回生成器地址<generator object <genexpr> at 0x000001E17AF23BA0>
print(next(laomuji)) #输出结果为:鸡蛋0
print(laomuji.__next__()) #输出结果为:鸡蛋1
print(next(laomuji)) #输出结果为:鸡蛋2
#next(laomuji)等价于laomuji.__next__()
3、字典推导式
#将字典键与值对调
mcase = {'a': 10, 'b': 34}
print({mcase[k]:k for k in mcase})
4、集合推导式
自带去重功能,将列表解析式的[]换成{}得到集合推导式
print({i*i for i in [1,-1,2]}) #结果为{1,4}
1.把列表解析的[]换成()得到的就是生成器表达式
2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存
3.Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和:
sum(x ** 2 for x in range(4))
而不用多此一举的先构造一个列表:
sum([x ** 2 for x in range(4)])
生成器面试题
def demo():
for i in range(4):
yield i
g=demo() # 生成器
g1=(i for i in g) #生成器
g2=(i for i in g1) #g2 生成器
# print(list(g1)) #[0,1,2,3]
print(list(g2))
def add(n,i):
return n+i
def tes():
for i in range(4):
yield i
g=tes()
for n in [1,5,10]:
g=(add(n,i) for i in g)
n=1
g=(add(n,i) for i in tes()) #---> g=(add(n,i) for i in g) 生成器,没要,不会给值 -->tes() = g
n = 5
g=(add(n,i) for i in (add(n,i) for i in tes()))
n = 10
g=(add(n,i) for i in (add(n,i) for i in (add(n,i) for i in tes())))
# g=(30,31,32,33)
print(list(g))

浙公网安备 33010602011771号