迭代器与生成器,及生成器进阶和相关表达式
Posted 小杜要加油
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了迭代器与生成器,及生成器进阶和相关表达式相关的知识,希望对你有一定的参考价值。
一、迭代器(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))
以上是关于迭代器与生成器,及生成器进阶和相关表达式的主要内容,如果未能解决你的问题,请参考以下文章
Python100天学习笔记Day20 迭代器与生成器及 并发编程