迭代器与生成器
- 迭代器
'''
什么是可迭代对象
1.可迭代对象用来:for in 循环
2. list,dict,tuple,str,set
3.需要满足:__iter__的方法,并且这个方法要返回一个迭代器对象
什么是迭代器
1.用来返回数据,每次循环都会调用迭代器的__next__或者next方法,通过这个方法来获取数据
2.需要满足条件:在Python2中:需要实现__iter__,next
在Python3中,需要实现__iter__和__next__方法
iter函数:
用来获取一个可迭代对象的迭代器
'''
from collections.abc import Iterable,Iterator
# ret = [1,2,3]
# ret1 = (1,2,3)
# ret2 = 'abc'
# ret3 = 123
#
# print(isinstance(ret,Iterable))
# print(isinstance(ret1,Iterable))
# print(isinstance(ret2,Iterable))
# print(isinstance(ret3,Iterable))
# #判断一个对象是否是一个可迭代对象
# class MyRange(object):
# def __iter__(self):
# pass
#
# ret4 = MyRange()
# print(isinstance(ret4,Iterable))
# #判断一个对象是否是迭代器对象
# class MyRange(object):
# def __iter__(self):
# pass
#
# def __next__(self):
# pass
#
# ret = MyRange()
# print(isinstance(ret,Iterator))
#自定义一个迭代器
#类似于list或者类似于range的对象
#range(1,10)
class MyRangeIterator(object):
def __init__(self,start,end):
self.index = start
self.end = end
def __iter__(self):
return self
def __next__(self):
if self.index < self.end:
temp = self.index
self.index += 1
return temp
else:
raise StopIteration()
class MyRange(object):
'''
MyRange是可迭代对象
'''
def __init__(self,start,end):
self.start = start
self.end = end
def __iter__(self):
#这个方法中要返回一个迭代器对像
return MyRangeIterator(self.start,self.end)
ret = MyRange(1,10)
for x in ret:
print(x)
print('='*30)
for y in ret:
print(y)
#for ... in ... 的原理
# ret_iterator = iter(ret)
# while True:
# try:
# x = ret_iterator.__next__()
# print(x)
# except StopIteration:
# break
#
# class MyRange(object):
# '''
# MyRange是可迭代对象
# '''
# def __init__(self,start,end):
# self.start = start
# self.end = end
# self.index = start
#
# def __iter__(self):
# #这个方法中要返回一个迭代器对像
# return self
#
# def __next__(self):
# if self.index < self.end:
# temp = self.index
# self.index += 1
# return temp
# else:
# raise StopIteration()
#
# ret = MyRange(1,10)
# for x in ret:
# print(x)
#
# print('='*30)
# for y in ret:
# print(y)
'''
如果将迭代器和迭代对象都放在一个对象中,那么只可以迭代一次
'''
- 生成器
'''
为什么用生成器:节省内存
生成器运行原理:yield会一次返回一个结果,并且会冻结当前函数的状态
解决问题:
1.用Python圆括号的方式
2.使用自定义函数
生成器其实也是迭代器,也是可迭代对象,那么可以通过for循环进行遍历,
并且因为他自身集成了迭代器和可迭代对象两个身份,因此他只能被遍历一次。
'''
# ret = [x for x in range(1,1000000000)]
# for x in ret:
# print(x)
# ret = (x for x in range(1,100000000))
# print(type(ret))
# for x in ret:
# print(x)
#生成器解决内存满,自定义生成器
# def my_gen():
# yield 1
# yield 2
# yield 3
#
# ret = my_gen()
# # print(type(ret))
# print(next(ret))
# print(next(ret))
# print(next(ret))
# print(next(ret))
def my_gen(start,end):
index = start
while index <= end:
yield index
index += 1
#生成器有两个身份,迭代器和可迭代的对象
ret = my_gen(1,10000000)
for x in ret:
print(x)
# a = 1+2 #右边是表达式
# b = 3
# c = a+b #右边是表达式
def my_gen(start):
while start < 10:
#如果是通过next函数执行yield
#那么yield xxx 永远都是返回None
temp = yield start
print(temp)
start += 1
'''
send方法:
1.也是用来触发代码,直到碰到yield表达式
2.如果用send方法执行刚刚开始的生成器,那么应该传None给send方法。不传或者传其他值都会报错
send与next区别:
1.send方法可以传递值给yield表达式。
2.第一次执行时,send要传None,而next不用。
'''
ret = my_gen(1)
print(ret.send(None))
print(ret.__next__())
#1
print(ret.__next__())
#temp
#2
print(ret.send('zhiliao'))#传递值给yield表达式
#zhiliao
#3
# #生成器中少用return
# def my_gen():
# print('hello')
# yield 1
# return
# yield 2
#
# ret = my_gen()
# print(next(ret))
# print(next(ret))
#菲波那切数列
# def fib(count):
# index = 1
# a,b = 0,1
# while index <= count:
# yield b
# c = b
# b = a+b
# a = c
#
# index += 1
# for x in fib(7):
# print(x)
def neteasy_musice(duration):
time = 0
while time <= duration:
print('歌曲听到了第%d分钟了' % time)
time += 1
yield None
def youku_movie(duration):
time = 0
while time <= duration:
print('电影看到第%d分钟了' % time)
time += 1
yield None
if __name__ == '__main__':
music_iter = neteasy_musice(10)
movie_iter = youku_movie(20)
music_stop = False
movie_stop = False
while True:
try:
next(music_iter)
except StopIteration:
print('音乐已经播完')
music_stop = True
try:
next(movie_iter)
except StopIteration:
print('电影已经看完')
movie_stop = True
if movie_stop and music_stop:
break