学习协程之前先来学习几个知识点:
迭代
使用for循环遍历取值的过程叫做迭代,如使用for循环遍历列表获取值的过程
可迭代对象:使用for循环遍历取值的对象叫做可迭代对象, 比如:列表、元组、字典、set、range、字符串
判断对象是否是可迭代对象:
from collentions import Iterable
result = isinstance((3, 5), Iterable) # 返回True
那么如何自己来定义一个可迭代对象?
自定义可迭代对象:在类里面定义__iter__() 方法创建的对象就是可迭代对象
但是遍历可迭代对象依次获取值需要迭代器。
在类里定义__iter__()方法创建的对象就是可迭代对象,可迭代对象 需要迭代器完成取数据的操作。
可迭代对象的本质是通过迭代器完成取值操作的。
可迭代对象的本质:遍历可迭代对象的时候其实获取的是可迭代对象的迭代器, 然后通过迭代器获取对象中的数据
迭代器
在类里定义__iter__()和__next__()方法创建的对象就是迭代器对象 from collections import Iterator
from collections import Iterable
from collections import Iterator
# 自定义可迭代对象
class MyIterable(object):
def __init__(self):
# 创建列表,存储添加的数据
self.my_list = list()
# 添加数据
def append_item(self, item):
self.my_list.append(item)
def __iter__(self):
# 可迭代对象的本质是通过迭代器完成取值操作的
# 这里需要返回一个迭代器
my_iterator = MyIterator(self.my_list)
# 判断对象是否是迭代器对象
#result = isinstance(my_iterator, Iterator)
#print("my_iterator是否是迭代器类型对象:", result)
return my_iterator
# 自定义迭代器对象: 在自定义类里面提供一个__iter__和一个__next__的方法创建的对象就是自定义迭代器对象
# 迭代器是可以完成取值操作的
class MyIterator(object):
def __init__(self, my_list):
self.my_list = my_list
# 记录取值的下标
self.current_index = 0
# 需要返回一个迭代器
def __iter__(self):
#返回自身
return self
# 通过next方法获取迭代器中的下一个值
def __next__(self):
if self.current_index < len(self.my_list):
value = self.my_list[self.current_index-1]
# 对下标加1
self.current_index += 1
return value
else:
# 下标越界,需要抛出停止迭代异常,表示取值完成
raise StopIteration
# 创建自定义可迭代对象
my_iterable = MyIterable()
# 添加数据
my_iterable.append_item(1)
my_iterable.append_item(2)
# 判断对象是否是可迭代对象
result = isinstance(my_iterable, Iterable)
print("my_iterable是否是可迭代类型对象:", result)
# 遍历可迭代对象,依次获取添加的数据
for value in my_iterable:
print(value)
iter()函数与next()函数
- iter函数: 会调用可迭代对象身上的
__iter__
方法,获取可迭代对象的迭代器 - next函数: 会调用迭代器对象身上的
__next__
方法,获取迭代器中下一个值
for循环的本质
遍历的是可迭代对象
- for item in Iterable 循环的本质就是先通过iter()函数获取可迭代对象Iterable的迭代器,然后对获取到的迭代器不断调用next()方法来获取下一个值并将其赋值给item,当遇到StopIteration的异常后循环结束。
next(iter(Iterable)) 可以取值
遍历的是迭代器
- for item in Iterator 循环的迭代器,不断调用next()方法来获取下一个值并将其赋值给item,当遇到StopIteration的异常后循环结束。
next(Iterator)可以取值
# 自定义可迭代对象: 在类里面定义__iter__方法创建的对象就是可迭代对象
class MyList(object):
def __init__(self):
self.my_list = list()
def append_item(self, item):
self.my_list.append(item)
def __iter__(self):
my_iterator = MyIterator(self.my_list)
return my_iterator
# 迭代器是记录当前数据的位置以便获取下一个位置的值
class MyIterator(object):
def __init__(self, my_list):
self.my_list = my_list
self.current_index = 0
def __iter__(self):
return self
# 获取迭代器中下一个值
def __next__(self):
if self.current_index < len(self.my_list):
self.current_index += 1
return self.my_list[self.current_index ]
else:
# 数据取完了,需要抛出一个停止迭代的异常
raise StopIteration
# 创建了一个自定义的可迭代对象
my_list = MyList()
my_list.append_item(1)
my_list.append_item(2)
# 获取可迭代对象的迭代器
my_iterator = iter(my_list)
print(my_iterator)
# 获取迭代器中下一个值
# value = next(my_iterator)
# print(value)
# 循环通过迭代器获取数据
while True:
try:
value = next(my_iterator)
print(value)
except StopIteration as e:
break
迭代器好处:
- 节省内存,每次根据算法只会生成一个数据,也就是说只占用一个变量的内存空间
- 不会受到生成数列个数的影响
demo 迭代器完成斐波那契数列
# 自定义迭代器
class Fibonacci(object):
def __init__(self, num):
# num: 表示创建斐波那契数列的个数
self.num = num
# 记录数列的前面两个值
self.first_value = 0
self.second_value = 1
# 记录生成个数的下标
self.current_index = 0
def __iter__(self):
return self
def __next__(self):
if self.current_index < self.num:
# 临时存储第一个变量的值
result = self.first_value
# 根据算法生成对应的数列的值
self.first_value, self.second_value = self.second_value, self.first_value + self.second_value
self.current_index += 1
return result
else:
raise StopIteration
# 创建迭代器
fib = Fibonacci(5)
# value = next(fib)
#
# print(value)
#
# value = next(fib)
#
# print(value)
for value in fib:
print(value)
生成器
生成器是一类特殊的迭代器,它不需要再像上面的类一样定义__iter__和__next__方法,但它依然可以使用next函数和for 循环取值。
创建生成器的方法:
- 将列表生成式的[]改成()
- 在def函数里看到有yield关键字那么就是生成器
在使用生成器实现的方式中,我们将原本在迭代器
__next__
方法中实现的基本逻辑放到一个函数中来实现,但是将每次迭代返回数值的return换成了yield,此时新定义的函数便不再是函数,而是一个生成器了。
demo 生成器完成斐波那契数列
def fibonacci(num):
first_value = 0
second_value = 1
# 记录生成个数的下标
current_index = 0
print("----111----")
while current_index < num:
result = first_value
first_value, second_value = second_value, first_value + second_value
current_index += 1
print("----222----")
# 当代码执行到yield关键字的时候代码会暂停,然后结果返回给外界,再次启动生成器会在暂停的位置继续往下执行
yield result
print("----333----")
generator = fibonacci(2)
print(generator)
#value = next(generator)
#print(value)
#value = next(generator)
#print(value)
for value in generator:
print(item)
使用send方法启动生成器并传参
send的好处是可以让用户传入参数,使生成器根据用户输入的参数不同,做出不同操作。
第一次使用send启动生成器时只能传入None,所以推荐第一次启动生成器使用next。
def fibonacci(num):
# num: 表示使用生成创建斐波那契数列的个数
# 记录数列前面两个值
first_value = 0
second_value = 1
# 记录生成个数的下标
current_index = 0
print("----111----")
while current_index < num:
result = first_value
first_value, second_value = second_value, first_value + second_value
current_index += 1
print("----222----")
# 当代码执行到yield关键字的时候代码会暂停,然后结果返回给外界,再次启动生成器会在暂停的位置继续往下执行
# 第二次启动生成器的时候传入的参数赋值给params变量
params = yield result
print(params)
if params == "ok":
return
print("----333----")
fib = fibonacci(5)
value = next(fib)
print(value)
# send方法启动传入参数给生成器
value = fib.send("传入的参数")
print(value)
value = fib.send("传入的参数")
print(value)
# value = fib.send("ok") # 抛出StopIteration的错误
# print(value)
----111----
----222----
0
传入的参数
----333----
----222----
1
传入的参数
----333----
----222----
- 生成器创建有两种方式,一般都使用yield关键字方法创建生成器
- yield特点是代码执行到yield会暂停,把结果返回出去,再次启动生成器在暂停的位置继续往下执行