Loading

Python迭代器和生成器

迭代器

可迭代对象:指的是定义了__iter__ 方法的对象,调用该方法会返回一个迭代器对象,例如list,tuple,set,dict等。

迭代器:不仅要实现__iter__方法,还需要实现__next__方法。可以通过调用next()方法,来获取数据。

生成迭代器:

  1. iter(可迭代对象)
  2. 可迭代对象.__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>

调用迭代器:

  1. next(可迭代对象)

  2. 可迭代对象.__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)
posted @ 2021-07-05 09:47  charlatte  阅读(45)  评论(0编辑  收藏  举报