一、迭代器
1、可迭代对象(iterable)
a>常见可迭代对象:列表、元组、字典、字符串都是可迭代的,而整数、浮点型数据、布尔数都是不可迭代的。通过for...in...这类语句迭代读取一条数据供我们使用的对象称之为可迭代对象(iterable)
b>通过isinstance()判断一个对象是否可以迭代
参考代码:
2、可迭代对象的本质
a>、可迭代对象的本质就是提供迭代器帮助我们对其进行迭代使用
b>、可迭代对象取得迭代器
可通过迭代对象(Iterable)的__iter__()魔法方法取得迭代器
c>、如何定义可迭代类,参考代码如下:
3、iter()和next()函数
前者需要传入一个可迭代对象,然后,再返回一个迭代器,内部通过可迭代对象的__iter__()方法取得迭代器;后者传入一个迭代器,返回迭代器的下一个值
4、for..in... 循环本质:就是先通过iter()函数获取可以迭代对象的迭代器,然后对获取到的迭代器不断调用next(),来获取下一个值并将其赋值给item,当遇到StopIteration的异常后循环就结束
5、迭代器
1、迭代器是用于迭代数据的
记录每次访问的位置,以及返回下一个数据,迭代器通过__next__()方法取得下一个指向的值,默认从可迭代对象的第一个元素访问,知道所有元素访问结束,且迭代器只能向下迭代
2、迭代器就是一个可迭代对象
3、定义迭代器:
定义类,添加__next__(), 添加__iter__()
参考代码如下:
import collections class MyClassmate(object): def __init__(self): self.names = [] self.position = 0 def add(self, name): self.names.append(name) def __iter__(self): # 返回迭代器, 先来个空实现 return self def __next__(self): if self.position < len(self.names): item = self.names[self.position] self.position += 1 return item else: raise StopIteration classmate = MyClassmate() classmate.add('小王') classmate.add('小李') classmate.add('小何') print(isinstance(classmate, collections.Iterable)) for item in classmate: print(item) 6、迭代器的应用场景 1、用于迭代可迭代的对象数据 2、因为迭代器是通过__next__来获取迭代的数据的,所有可以通过__next__自动生成有规律的数据,而不用在已有的数据集合去取数,避免内存资源的浪费
示例: 编写斐波那契数列迭代器:
要求:传入一个n值,就能输出前n个斐波那契数列值 斐波那契数列描述: 数列中第一个数为0,第二个数为1,其后的每一个数都可由前两个数相加得到: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...7、总结:
1、通常用 for...in能迭代出下一个数据的对象称为可迭代对象
2、具备了__iter__方法的对象就是可迭代对象
3、迭代器也是可迭代对象
定义迭代器,需要添加__next__()、__iter__()方法
4、通过迭代器可以自动生成一些规律的数据
二、生成器
1、生成器介绍
生成器是一种特殊的迭代器,他比迭代器更优雅,编写更加简洁
2、创建生成器方法1
列表生成式
# 列表推导式
L=[ x*x for x in range(5)]print(L)# 简单的生成器的实现方式: 列表生成式 ,把列表推导式[]改为()
G=( x*x for x in range(5))print(G)# 生成器是迭代器,是可迭代对象
# 使用next迭代数据print(next(G))print(next(G))print(next(G))print(next(G))print(next(G))# 使用for ...in 迭代
G1=( x*x for x in range(10))for item in G1: print(item)b>、yield实现生成器
1、函数中有yield,则不再是函数,而是生成器
2、yield会产生一个断点,暂停函数,挂起函数,且保存当前状态
3、假如yield后面紧接着一个数据,就会把该数据返回,作为next()函数或者for..in...迭代出下一个值
4、可以通过next()唤醒生成器,让生成器从断点继续执行
在函数中加yield,实现复杂的生成器:
c> yield实现生成器的执行过程
""" 1.生成器默认是沉睡的,可通过next唤醒生成器 2. 第一次唤醒生成器时,是从生成器(函数)的起始位置开始,直到遇到yield,就会暂停函数,挂起函数 3. 第二次唤醒生成器时,是从yield断点处开始,直到又遇到yield 4. 当生成器已经没有yield,再使用next,则抛StopIteration异常 """yield生成器的执行过程代码如下:
# 使用yield实现生成器
def fib(n): print("--1--") positon = 0 # 记录当前迭代的位置,初始值是0 num1,num2=0,1# 记录数列中的前两个数,初始值 是 0,1 while positon<n: # print(num1) print("--2--") """ 1. 假如函数中有yield,则不再是函数,而是生成器 2. yield 会产生一个断点,暂停函数 ,挂起函数, 且保存当前状态 3. 假如yield后面紧接着一个数据,就会把数据返回, 作为next()函数或者for ...in...迭代出的下一个值 4. 可以通过next()唤醒生成器,让生成器从断点处继续执行 假如第一次唤醒生成器,则从生成器(函数)的起始位置开始 """ yield num1 print("--3--") num1,num2=num2,num1+num2 positon+=1 # 自加1 ,指向下一个位置 print("--4--") # 创建生成器对象 ,生成器默认是沉睡的状态gen=fib(3)# 生成器也是迭代器,也是可迭代对象
# next来迭代print("返回值:",next(gen))print("返回值:",next(gen))print("返回值:",next(gen))# print("返回值:",next(gen))"""
1.生成器默认是沉睡的,可通过next唤醒生成器2. 第一次唤醒生成器时,是从生成器(函数)的起始位置开始,直到遇到yield,就会暂停函数,挂起函数3. 第二次唤醒生成器时,是从yield断点处开始,直到又遇到yield4. 当生成器已经没有yield,再使用next,则抛StopIteration异常"""4.使用send唤醒生成器(generator) send与next唤醒生成器不同: 1. generator.send() 与next()都可以唤醒生成器,但send方法可传值给生成器的断点处 2. 使用: next(generator) :next是内置的函数 generator.send("你好") # send是生成器中的方法 3. generator.send(None)等价于next(generator) 4. 第一次唤醒生成器时,假如使用send,则只能传None,因为刚开始执行生成器时,是没有断点的
send与next唤醒生成器代码如下:
# 使用yield实现生成器
def fib(n): print("--1--") positon = 0 # 记录当前迭代的位置,初始值是0 num1,num2=0,1# 记录数列中的前两个数,初始值 是 0,1 while positon<n: # print(num1) print("--2--") """ 1. 假如函数中有yield,则不再是函数,而是生成器 2. yield 会产生一个断点,暂停函数 ,挂起函数, 且保存当前状态 3. 假如yield后面紧接着一个数据,就会把数据返回, 作为next()函数或者for ...in...迭代出的下一个值 4. 可以通过next()唤醒生成器,让生成器从断点处继续执行 假如第一次唤醒生成器,则从生成器(函数)的起始位置开始 """ temp=yield num1 # 1. yield num1 # 2. temp=xxx print("传入到断点的参数:",temp) print("--3--") num1,num2=num2,num1+num2 positon+=1 # 自加1 ,指向下一个位置 print("--4--") # 创建生成器对象 ,生成器默认是沉睡的状态gen=fib(3)# 生成器也是迭代器,也是可迭代对象
# next来迭代# print("返回值:",next(gen))# print("返回值:",gen.send("test"))print("返回值:",gen.send(None))# send方式唤醒生成器,可以向yield断点处传值
print("返回值:",gen.send("python"))print("返回值:",gen.send("itcast"))"""
send与next唤醒生成器不同: 1. generator.send() 与next()都可以唤醒生成器,但send方法可传值给生成器yield的断点处 2. 使用: next(generator) :next是内置的函数 generator.send("你好") # send是生成器中的方法 3. generator.send(None)等价于next(generator) 4. 第一次唤醒生成器时,假如使用send,则只能传None,因为刚开始执行生成器时,是没有yield断点的"""