一、迭代器
拥有__iter_方法和__next__方法的对象就是迭代器
1、迭代
迭代是访问集合元素的一种方式,可以将某个数据集内的数据’一个挨着一个取出来’就叫做迭代
2、可迭代协议
协议就是互相规定好的,可迭代协议的定义非常简单,就是内部实现__iter__。
方法。
3、协议迭代器
必须拥有__iter__方法和__next__方法。
4、能被for 循环的内容
list、dic、str、set、tuple、range()、enumerate、f.open()
for i in 123:#报错整数不可迭代的
# pass
5、dir()方法获取对相应数据类型的所有方法。
dir()获取对应数据类型的所有方法,带有下划线的方法叫做双下方法,例如print(dir([]))
6、查看[],{},’’,range()共有的方法
使用集合的交集进行获取找到__iter__方法。有此方法的对象就是一个可以被迭代的对象
ret=set(dir([]))&set(dir({}))&set(dir(''))&set(dir(range(2)))
print(ret)
print('__iter__'in dir(int))#False int中的数据类型方法没有__iter__
print('__iter__'in dir(bool))#False 同上
7、__iter__方法的作用是返回一个迭代器。
一个列表执行了__iter__()方法后返回值就是一个迭代器
print([].__iter__())#<list_iterator object at 0x00000000007400F0>
8、打印一下迭代器中的方法
t=set(dir([].__iter__()))-set(dir([]))
print(t)
#{'__next__', '__length_hint__', '__setstate__'}
setstate:决定取值的位置
length_hint :获取元素的个数
next:获取元素
9、for 循环原理
1、for循环一个可迭代的对象(实现__iter__方法)
2、__iter__方法返回一个迭代器(迭代器实现了__iter__方法和__next__方法)
3、先判断对象地方可迭代,然后调用迭代器的__next__方法获取值
10、利用迭代器求斐波那契数列
class Fibonacci(object):
def __init__(self, all_num):
self.all_num = all_num
self.a = 1
self.b = 1
self.current_num = 0
def __iter__(self):
return self # 返回自己 调用 自己的__next__()方法
def __next__(self):
if self.all_num <= 2:
self.current_num += 1 # 1,2,3
if self.current_num == 3:
raise StopIteration
return self.a
else:
if self.current_num < self.all_num:
ret = self.a # 1
self.a, self.b = self.b, self.a + self.b
# a=1, b=2
# a=2, b=3
self.current_num += 1
return ret
else:
raise StopIteration
for i in Fibonacci(10):
print(i)
11、迭代器作用和应用场景
1、节约内存,取得时候在生成数据,
2、数据类型转换 例如list和元组之间的转换底层就是使用的迭代器
**
二、生成器
**
生成器的本质就是迭代器;生成器包括两种:生成器函数和生成器表达式
1、生成器函数
一个包含yield关键字的函数就是一个生成器函数。并且yield不能和return共用,并且yield
只能用在函数内。
1)生成器函数执行后会得到一个生成器作为返回值,并且不会执行函数体。
2)执行了__next__()方法之后才会执行函数体,并且获得返回值。
3)next()内置方法,内部调用生成器函数的__next__()方法。
4)yield和return相同的是可以返回值,但是不同的是yield不会结束函数
练习1、创建一个生成器并且调用
def generator():
print('zzz')
yield
ret=generator()
print(ret)#返回一个生成器对象,并没有执行生成器中的函数体
ret.__next__()#调用__next__()方法执行生成器
练习2:创建一个生成器,并且设置返回值
def generator():
print('zzzz')
yidld 1#添加返回值
ret=generator()
res=ret.__next__()
print(res)
练习3:创建生成器,定义多个yield值
def generator():
print('zzzz')
yield 1
print('xxxx')
yield 2
ret=generator():
res=ret.__next__()
print('--------->>>',res)
res=ret.__next__()
print('--------->>>',res)
练习4:创建生成器,生成200万桶康师傅方便面。
def ksf():
for i in range(2000000):
yield'康师傅方便面%s' % i
generator=ksf()
for i in generator:
print(i)
2、send()
send() 获取下一个值的效果和next()基本一致,只是在获取下一个值的时候,给上一个yield的位置传递一个数据
使用send的注意事项
1)第一次使用生成器的时候 ,是用next获取下一个值
2)最后一个yield不能接受外部的值
练习1:使用send()方法给yield传递参数
def generator():
peint('a')
count=yield 1
print('------>',count)
print('b')
yield 2
g=generator()
next(g)
ret2=g.send('123')
print(ret2)
练习2:计算移动平均值
def fun_avg():
count=1
get_num=0
acg=0
total=0
while True:
get_num=yield avg
total=total+get_num
avg=total/count
count+=1
g=fun_avg()
next(g)
print(g.send(10))#打印10
print(g.send(20))#打印15
print(g.send(30))#打印20
3、yield form
刚知道了yield,那么yield from又是什么呢? 它是循环遍历容器类型
现在做一个练习,用for循环取出g1生成器中所有的值。
def gen1()
for c in 'ab':
yield c
for i in range(3):
yield i
g=gen1()
for i in g:#用for循环遍历出gen1()中的值
print(i)
print(list(gen1()))#直接将遍历出来的值赋值到列表中
现在我们再用yield from 遍历出可变数据类型中的数据
def gen2():
yield from 'ab'
yield from range(3)
g=gen2()
for i in g:
print(i)
print(list(gen2()))
4、生成器表达式
生成器表达式,跟列表推导式差不多
格式:将列表解析式[]改成()即可。
我们来用生成器表达式进行数数,如下:
g=(i for i in range(10))
print(g)
for j in g:
print(j)
我们再来模拟鸡下蛋再进行一个练习:
首先使用列表推导式生成
egg_list=['鸡蛋{}'.format(i)for i in range(10)]
print(egg_list)#你会发现列表会一下堆满了‘鸡蛋’
使用生成器表达式再来一次
egg_list=('鸡蛋{}'.format(i)for i in range(10))
print(egg_list)
print(next(egg_list))#调用一次next打印一个1个‘’鸡蛋‘’
print(egg_list.__next__())
print(next(egg_list))
print(egg_list)
print(list(egg_list))