博主前言:
「2020本来是充满希望,收获幸福的一年。可没想到这一年的开始就如此的惨烈、痛苦。在此,博主真诚的祝福那些身处在抗疫一线的白衣天使们能够平稳健康,给他(她)们致以最崇高的敬意」
这篇博客讲述Python中的迭代器和生成器,内容较抽象,希望读者结合代码好好理解。
1. 迭代器
迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。
每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值。
在计算机中重复执行程序中的循环,直到满足某条件为止,亦称为迭代。
1.1 iter()
Python语言中,在定义一个类时,如果在类中定义了iter()函数,
那么这个类就是可迭代的类,
由这个类所实例化的对象就是可迭代的对象。
在Python语言中,可调用collections模块的Iterable中的isinstance()函数判断当前对象是否可迭代。
from collections import Iterable
class IterableClass(object):
"""定义一个可迭代的类"""
def __init__(self,name,nubmer): # 构造函数
self.name = name
self.number = nubmer
def __iter__(self): # 定义iter函数,伪代码
pass
def main():
test = IterableClass("tomato",2020)
print("判断test是否可迭代:%s" % isinstance(test,Iterable))
if __name__ == '__main__':
main()
当我们运行上述代码时,结果如下:
可当我们把定义的iter函数注释掉后再运行时代码,结果会大相径庭。
# def __iter__(self): # 定义iter函数,伪代码
# pass
由此可知:
当类中定义了iter函数时,那么由该类实例化的对象是可迭代的。
当类中没有定义iter函数时,由该类实例化的对象就不可迭代(例整型)。
1.2 next()
在类定义时,同时定义了iter函数和next函数的类,其所实例化的对象称为迭代器对象。
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator
在Python语言中,可调用collections模块的Iterable中的isinstance()函数判断当前对象是否为迭代器对象(代码实现如上段)
接下来,我们在定义一个迭代器类。
from collections import Iterable
class IteratorClass(object):
"""定义一个迭代器类"""
def __init__(self): # 构造函数
self.g_number = 0
self.name = list()
self.number = list()
def AddMemmber(self,name,number): # 添加数据
self.name.append(name)
self.number.append(number)
def __iter__(self):
return self
def __next__(self):
if len(self.name) > self.g_number:
name = self.name[self.g_number]
number = self.number[self.g_number]
self.g_number += 1
return "姓名:"+name+", "+"学号:"+str(number)
else:
raise StopIteration
def main():
test = IteratorClass()
test.AddMemmber("tomato",2020)
test.AddMemmber("potato",2021)
test.AddMemmber("konato",2022)
for member in test:
print(member)
if __name__ == '__main__':
main()
运行上段代码,结果如以下图示。
主线程执行顺序:
- 定义一个迭代器类IteratorClass,实例化一个对象test
- 使用AddMemmber函数,将个人信息加入库中
- 执行迭代运算,从test对象中取出每个人的个人信息
- 在迭代运算中(即for循环),迭代器对象会自动调用类中的iter函数,iter函数的返回值是一个迭代器。在此代码中,test对象的iter函数的返回值为自身,因为test对象自身就是一个迭代器对象
- 调用迭代器的next函数来取值,一次迭代调用一次next函数。
- Python中的迭代器协议就是每次调用next函数的对象会前进到下一个结果,
而在迭代器中的值取完时则会抛出StopIteration异常。
2. 生成器
生成器是一种特殊的迭代器。
例:
列表生成式: | [ x*2 for x in range()10 ] |
---|---|
列表生成器: | ( x*2 for x in range()10 ) |
2.1 yield
在函数定义时,若函数体中存在关键字yield,
那么该函数就是一个生成器模板,
调用该函数,就是创建一个生成器对象。
yield后面是谁,就把谁return,再次调用时从上次yield的地方继续执行。
最后,我们用代码来实现一下黄体字的编程逻辑:
g_number = 10 # 定义一个全局变量g_number
def generator(): # 定义一个生成器模板
global g_number
while True:
print("----- 1 -----")
print("当前number的值为:",g_number)
yield g_number
g_number -= 1
print("当前number的值为:",g_number)
print("----- 2 -----")
def main():
test = generator()
next(test)
if __name__ == '__main__':
main()
因为迭代器都能通过调用next()函数使其运行,
生成器是一种特殊的迭代器,
所以这里的生成器对象test同样调用next函数来运行。
运行上述代码,结果如以下图示:
当我们修改main函数,将next函数运行两次,这时得到的结果如以下图示:
def main():
test = generator()
next(test)
next(test)
由此,我们可以看出在函数定义中,
yield后面是谁,就把谁return,再次调用时从上次yield的地方继续执行,
当再次运行到yield时,再次将yield后面的值return。