Python迭代器和生成器
迭代器
可迭代对象:指的是定义了__iter__
方法的对象,调用该方法会返回一个迭代器对象,例如list,tuple,set,dict等。
迭代器:不仅要实现__iter__
方法,还需要实现__next__
方法。可以通过调用next()
方法,来获取数据。
生成迭代器:
iter(可迭代对象)
可迭代对象.__iter__()
注:iter()
函数能够把可迭代对象转化为迭代器。
示例:
list1 = [1, 2, 3, 4]
list2 = iter(list1)
print(list2) # <list_iterator object at 0x00000240B6A63BC8>
print(type(list2)) # <class 'list_iterator'>
set1 = {"a", 1, "b", 2}
set2 = iter(set1)
print(set2) # <set_iterator object at 0x000002A93FDA2728>
print(type(set2)) # <class 'set_iterator'>
my_tuple = ("a", "b", "c")
print(my_tuple.__iter__()) # <tuple_iterator object at 0x0000023A0C777548>
调用迭代器:
-
next(可迭代对象)
-
可迭代对象.__next__()
注:next()
函数不断调用并返回下一个值,直到最后抛出StopIteration
错误表示无法继续返回下一个值。
list1 = [1, 2, 3]
list2 = iter(list1)
# 通过next方法不断从前往后访问
print(next(list2))
print(next(list2))
print(next(list2))
# 无法继续返回下一个值,在调用会报StopIteration
print(next(list2))
判断是否是迭代器(Iterator)和可迭代对象(Iterable):
通过collections模块的可以来判断是否是迭代器或可迭代对象。
from collections.abc import Iterator, Iterable
list1 = [1, 2, 3]
print(isinstance(list1, Iterator)) # False
print(isinstance(list1, Iterable)) # True
list2 = iter(list1)
print(isinstance(list2, Iterator)) # True
print(isinstance(list2, Iterable)) # True
注:迭代器对象一定是可迭代对象,而可迭代对象不一定是迭代器对象。
遍历迭代器:
Python的 for 循环本质上就是通过不断调用 next()
函数实现的。
it = iter(range(10))
for i in it:
print(i)
生成器
生成器是一个用于创建迭代器的简单而强大的工具,生成器可以看做就是一种迭代器。生成器不是一次将所有的数据都生成,而是仅仅在需要时生成一个数据。当数据量过大时,可以节约大量的内存空间。
创建生成器的方式:
(1)生成器推导式
(2)生成器函数
生成器推导式
my_generator = (value * 2 for value in range(1, 5))
print(my_generator) # <generator object <genexpr> at 0x000001710BD44E48>
使用next函数获取生成器的下一个值:
my_generator = (value * 2 for value in range(1, 5))
print(my_generator) # <generator object <genexpr> at 0x000001710BD44E48>
print(next(my_generator)) # 2
print(next(my_generator)) # 4
print(next(my_generator)) # 6
print(next(my_generator)) # 8
# 当没有值时,会抛出StopIteration
print(next(my_generator))
生成器函数
当函数中有yield关键字存在时,这个函数就是生成器函数。
执行生成器函数时,函数体默认不会被执行,返回的是一个生成器对象:
def my_func():
print("abc")
yield 123
# 这里调用函数不会打印出abc
result = my_func()
print(result) # <generator object my_func at 0x00000245B0054DC8>
next()函数接受生成器对象,执行生成器函数中的代码:
def my_func():
print("abc")
yield 123
result = my_func()
print(result) # <generator object my_func at 0x00000245B0054DC8>
print(next(result)) # 123
当程序执行到yield关键字时,代码会暂停,并把结果返回:
def my_generator():
for i in range(3):
print("开始生成数据...")
# 当程序执行到yield关键字时,代码会暂停,并把结果返回。
yield i
print("数据生成结束...")
result = my_generator()
print(result)
# 这里只会打印0
print(next(result))
# 再次调用next函数时,程序会从上一次yield暂停的地方继续向下执行
print(next(result))
send()函数可以用来发送数据:
send()函数可以给上一个yield发送数据。
def my_generator():
print("start")
res = yield 111
print(res)
yield 222
my_gen = my_generator()
# 第一次调用只能默认发送None
print(my_gen.send(None))
print(my_gen.send("aaa"))
send和next的区别:
- next只能取值。
- send不但能取值,还能给上一个yield发送值。
yield from的用法:
yield from语句后面可以接可迭代对象、迭代器,甚至是生成器。
def my_gen():
list1 = ["a", "b", "c"]
# 接可迭代对象
yield from list1
gen = my_gen()
print(next(gen)) # a
print(next(gen)) # b
print(next(gen)) # c
案例:使用生成器来实现斐波那契数列
# num表示生成斐波那契数列的个数
def fibonacci(num):
a = 0
b = 1
current_index = 0
while current_index < num:
result = a
# 条件成立交换两个变量的值
a, b = b, a + b
current_index += 1
yield result
f = fibonacci(6)
for i in f:
print(i)