3.4协程
3.4.1迭代
(1)迭代:使用for循环遍历取值的过程叫做迭代
(2)可迭代对象:能够使用for循环遍历取值的对象叫做可迭代对象
(3)可迭代的对象有:列表,元组,字典,字符串,集合,range
(4)判断对象是否是可迭代对象
可以使用isinstance进行判断,isinstance可用来判断任意数据是否是指定数据类型。如果是指定数据类型则返回True,否则返回False。在判断对象是否是可迭代对象的时候需要导入:from collections import Iterable
如:result = isinstance([4, 6], Iterable)
print("列表是否是可迭代类型:", result)
# 判断对象是否是迭代器
# 此时需要导入:from collections import Iterator
result = isinstance(student_iterator, Iterator)
print("student_iterator:", result)
(5)自定义可迭代对象
在类里面提供__iter__的方法创建的对象就是可迭代对象
可迭代对象的本质:可迭代对象之所以能把数据迭代出来是通过迭代器完成的
(6)自定义迭代器对象
迭代器作用:记录当前数据的位置,以便获取下一个位置的值
自定义迭代器对象: 在类里面提供__iter__和__next__的方法创建的对象就是迭代器对象
(7)iter()函数与next()函数
可以通过iter()函数获取这些可迭代对象的迭代器。可以对获取到的迭代器不断使用next()函数来获取下一条数据。当已经迭代完最后一个数据之后,再次调用next()函数会抛出StopIteration的异常,来告诉所有数据都已迭代完成,不用再执行next()函数了。
iter()函数: 获取可迭代对象身上的迭代器, 会调用可迭代对象的__iter__方法
next()函数: 获取迭代器对象的下一个值, 会调用迭代器对象的__next__方法
(8)for.....in...的本质
for循环的本质: 如果遍历的对象是可迭代对象,那么会通过iter函数获取对应的迭代器,然后通过next函数获取迭代器中的每一个值
如果遍历的对象是迭代器,那么直接使用next函数获取迭代器中每一个值
for循环内部自己捕获停止迭代异常(StopIteration),while循环取值的时候没有捕获该异常
(9)并不是只有for循环能接收可迭代对象
除了for循环能接收可迭代对象,list、tuple等也能接收
(10)迭代器的应用场景
如:迭代器可完成斐波那契数列的生成
代码实现:
# 定义迭代器
class Fibonacci(object):
# num:表示要生成fibonacci数列的个数
def __init__(self, num):
self.num = num
# 保存前两个值
self.a = 0
self.b = 1
# 记录生成数字的下标
self.current_index = 0
def __iter__(self):
return self
def __next__(self):
if self.current_index < self.num:
result = self.a
self.a, self.b = self.b, self.a + self.b
self.current_index += 1
return result
else:
# 抛出停止迭代的异常
raise StopIteration
# 创建迭代器对象
fib = Fibonacci(5)
for value in fib:
print(value)
(11)扩展:获取默认支持递归的次数
import sys
count = sys.getrecursionlimit()
print(count)
# 设置递归次数
sys.setrecursionlimit(2000)
count = sys.getrecursionlimit()
print(count)
3.4.2生成器
生成器是一个特殊的迭代器,也就是说可以使用next和for循环获取生成器值
(1)创建生成器的方式1:把列表推导式的中括号改成小括号就是生成器
如:g = (i * 2 for i in range(5))
print(g)
# next取生成器的值
value = next(g)
print(value)
# for循环依次取生成器中的每一个值
for value in g:
print(value)
(2)创建生成器的方式2:在def里面包含yield关键字创建的对象就是生成器
注意:代码执行到yield会暂停,然后把结果返回出去,再次启动生成器是在暂停的位置继续往下执行。生成器使用return关键字没有问题,但是执行到return语句的时候会抛出停止迭代的异常。return关键字只能在python3里面支持,python2不支持return关键字
如:
.......
yield result
......
try:
# 启动生成器取下一个值
result = next(fib)
print(result)
except StopIteration as e:
# 获取return返回值
print(e.value)
总结:yield 和 return的区别
yield 特点:每次启动生成器的时候返回一次值,多次启动生成器可以返回多次值
return 特点:代码执行到return会抛出停止迭代的异常,只能返回一次值
(3)生成器应用场景
如:生成器可完成斐波那契数列的生成
代码实现:
# 定义生成器
def fibonacci(num):
# 保存前面两个值
a = 0
b = 1
# 记录生成的索引
current_index = 0
print("----11-----")
# 循环判断条件是否成立
while current_index < num:
result = a
a, b = b, a + b
current_index += 1
print("----22-----")
# 代码执行到yield会暂停,然后把结果返回出去,再次启动生成器是在暂停的位置继续往下执行
yield result
print("----333-----")
# 提示:函数直到return表示函数执行完成,后面有再多的代码也不执行
# return result
fib = fibonacci(5)
for value in fib:
print(value)
(4)send方法启动生成器传递参数
result = fib.send(None)
print(result)
result = fib.send("ok")
print(result)
注意:send启动生成器可以传参,但是第一次使用send启动生成器传的参数必须是None,因为第一次没有办法接收参数
提示:一般情况下第一次启动生成器使用next