随笔 - 105  文章 - 0  评论 - 0  阅读 - 40744

迭代器、生成器、可迭代对象

迭代器出现的原因

Python中的列表,有可能会占用很大的空间。而迭代器,它是每一次用__next__调用时才计算出值,这会节省内存空间。

迭代器、生成器、可迭代对象的关系

可迭代对象一般是列表、元组、字典、字符串等可以For循环的对象。可通过以下语句判断是不是可迭代对象。

1
2
3
4
from collections.abc import Iterator, Iterable
 
l = [1, 2, 3, 4, 5]
print(isinstance(l, Iterable))  # True

而且每个可迭代对象都有__iter__方法,并且此方法返回一个迭代器。
那么什么是迭代器呢?它与可迭代对象有什么关系?为什么for循环可以得出每人元素的值?那是因为可迭代对象有一个记录员,可记录当前位置。而这个记录员就是迭代器,迭代器需要实现__iter__、__next__这两个方法。可迭代对象可生成迭代器,如下:

1
2
3
l = [1, 2, 3, 4, 5]
it = iter(l)
print(isinstance(it, Iterator))  # True

每个迭代器都有__next__方法和__iter__方法。而生成器是迭代器的一种,除了有__next__方法以外,还要用到yield。yield一般会用到自定义的函数中,但调用此函数时不会执行,而是会生成生成器。要调用此函数,需要用到__next__方法。

for循环的本质

其实for循环一个可迭代对象,为我们做了以下事情
1、通过可迭代对象生成一个迭代器
2、调用迭代器的__next__方法,生成值
3、遇到错误时,就退出
以下程序就说明了这个问题

1
2
3
4
5
6
7
8
9
10
l = [1, 2, 3, 4, 5]
for i in l:
    print(i)
# 以上for循环等同于以下效果
it = iter(l)
while True:
    try:
        print(it.__next__())
    except StopIteration:
        break

自定义可迭代对象和迭代器

例子如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class List(object):  # 自定义可迭代对象,必须要有__iter__方法
    def __init__(self):
        self.item_list = []
 
    def append(self, val):
        self.item_list.append(val)
 
    def __iter__(self):  # 自定义,必须要返回迭代器,此处返回自定义迭代器ListIterator
        return ListIterator(self.item_list)
 
 
class ListIterator(object):  # 自定义迭代器,必须要定义__iter__和__next__方法
    def __init__(self, item_list):
        self.index = 0
        self.item_list = item_list
 
    def __iter__(self):
        return self
 
    def __next__(self):
        if self.index < len(self.item_list):
            i = self.index
            self.index += 1
            return self.item_list[i]
        else:
            raise StopIteration
 
 
my_list = List()
my_list.append('辉')
my_list.append('玲')
my_list.append('婧')
my_list.append('正')
for i in my_list:
    print(i)

生成器

例一、斐波那契数列
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def fib(m):
    n, a, b = 0, 0, 1
    while n < m:
        yield # 每一次用__next__调用时会在此结束,下一次调用时执行yield下面的语句
        a, b = b, a + b
        n += 1
 
 
f = fib(5# 生成生成器,不会调用,要调用就用__next__方法
# while True:
#     try:
#         print(f.__next__())
#     except StopIteration:
#         break
for i in f:
    print(i)
# 斐波那契数列结束

例二、经典的生产者、消费都模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def consumer(name):
    print('%s要准备吃包子了' % name)
    while True:
        n = yield
        print('%s吃了%s个包子' % (name, n))
 
 
def producer(name):
    print('%s准备制造包子了' % name)
    c1 = consumer('Daughter')
    c2 = consumer('Son')
    c1.__next__()
    c2.__next__()
    print('-' * 40)
    while True:
        time.sleep(3)
        print('%s已经制造了2个包子' % name)
        c1.send(1# 可发送给yield
        c2.send(1)
        print('-'*40)
 
 
producer('Father')
# 消费者、生产都模型结束
posted on   Treelight  阅读(128)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示