迭代
对list、tuple、str等类型的数据使用for...in...的循环语法从其中依次拿到数据进行使用,我们把这样的过程称为遍历,也叫迭代
可迭代对象
不是所有对象都能使用for ..in ,比如数字10,把可以通过for...in...这类语句迭代读取一条数据供我们使用的对象称之为可迭代对象(Iterable)
判断是否是可迭代对象
from collections.abc import Iterable
print(isinstance("hello", Iterable)) # True
print(isinstance({"name": "zhangsan", "age": 18}, Iterable)) # True
print(isinstance([11, 22, 33], Iterable)) # True
print(isinstance((10, 20, 30), Iterable)) # True
print(isinstance({1, 9, 0, 88}, Iterable)) # True
print(isinstance(10.5, Iterable)) # False
可迭代对象的本质:具备了__iter__方法的对象,就是一个可迭代对象
#该类没有实现__iter__方法,所以不是可迭代对象
class Student:
def __init__(self, age):
self.age = age
print(isinstance(Student(8), Iterable)) # False
#重写了__iter__方法
class Student:
def __init__(self, age):
self.age = age
def __iter__(self):
return self
print(isinstance(Student(8), Iterable)) # True
迭代器
本质就是一个实现了__iter__方法和__next__方法的对象,就是迭代器
判断是否是迭代器
from collections.abc import Iterator, Iterable
# 判断是否是迭代器,可迭代对象是Iterable不是迭代器(Iterator)
print(isinstance("hello", Iterator)) # False
print(isinstance({"name": "zhangsan", "age": 18}, Iterator)) # False
print(isinstance([11, 22, 33], Iterator)) # False
print(isinstance((10, 20, 30), Iterator)) # False
print(isinstance({1, 9, 0, 88}, Iterator)) # False
print(isinstance(10.5, Iterator)) # False
print("-----------------------------------------------")
# 调用一个对象的__iter__方法,或者调用iter()内置函数,可以获取到一个可迭代对象的迭代器,只能是可迭代对象才能调用,否则报错
print(isinstance(iter("hello"), Iterator)) # True
print(isinstance(iter({"name": "zhangsan", "age": 18}), Iterator)) # True
print(isinstance([11, 22, 33].__iter__(), Iterator)) # True
print(isinstance((10, 20, 30).__iter__(), Iterator)) # True
print(isinstance(iter({1, 9, 0, 88}), Iterator)) # True
# print(isinstance(iter(10.5), Iterator)) # 报错 TypeError: 'float' object is not iterable
print("-----------------------------------------------")
class Student:
def __init__(self, age):
self.age = age
def __iter__(self):
return self
def __next__(self):
pass
print(isinstance(Student(8), Iterator)) # True
for ...in...循环的本质
for item in Iterable 循环的本质就是①先通过iter()函数获取可迭代对象Iterable的迭代器,②然后对获取到的迭代器不断调用next()方法来获取下一个值并将其赋值给item,③当遇到StopIteration的异常后循环结束
生成器
利用迭代器,我们可以在每次迭代获取数据(通过next()方法)时按照特定的规律进行生成。但是我们在实现一个迭代器时,关于当前迭代到的状态需要我们自己记录,进而才能根据当前状态生成下一个数据。为了达到记录当前状态,并配合next()函数进行迭代使用,我们可以采用更简便的语法,即生成器(generator)。生成器是一类特殊的迭代器
总结就是:
- 生成器是一类特殊的迭代器
- 只要在def中有yield关键字的 就称为 生成器
创建生成器方法1
g = (i * 2 for i in range(5))
print(g) # <generator object <genexpr> at 0x0000000002581CF0>
print(next(g)) # 0
print(next(g)) # 2
print(next(g)) # 4
print(next(g)) # 6
print(next(g)) # 8
print(next(g)) # 报错 StopIteration
#也可以使用for i in g 的方式遍历
创建生成器方法2
def generate_test(n):
result = []
for i in range(n):
result.append(i * 2)
yield result
g = generate_test(5)
print(g)
print(next(g)) # [0]
print(next(g)) # [0,2]
print(next(g)) # [0,2,4]
print(g.__next__()) # [0,2,4,6]也可以使用__next__方法,只是用的相对较少
print(g.__next__()) # [0,2,4,6,8]也可以使用__next__方法,只是用的相对较少
#print(g.__next__()) # 报错 StopIteration
#也可以使用for in
for i in g:
print(i)
生成器总结
- 使用了yield关键字的函数不再是函数,而是生成器。(使用了yield的函数就是生成器)
- yield关键字有两点作用:
- 保存当前运行状态(断点),然后暂停执行,即将生成器(函数)挂起
- 将yield关键字后面表达式的值作为返回值返回,此时可以理解为起到了return的作用
可以使用next()函数让生成器从断点处继续执行,即唤醒生成器(函数)