[Python学习]Iterator 和 Generator的学习心得

本文探讨了Python中迭代器(Iterator)与生成器(Generator)的概念及其应用。介绍了两者之间的区别,展示了如何使用生成器简化树形结构的遍历,并讨论了自定义迭代器的方法。

Iterator是迭代器的意思,它的作用是一次产生一个数据项,直到没有为止。这样在 for 循环中就可以对它进行循环处理了。那么它与一般的序列类型(list, tuple等)有什么区别呢?它一次只返回一个数据项,占用更少的内存。但它需要记住当前的状态,以便返回下一数据项。它是一个有着next()方法的对象。而序列类型则保存了所有的数据项,它们的访问是通过索引进行的。

使用Iterator的好处除了节省内存外,还有一个好处就是可以把非线性化的处理转换成线性化的方式来进行处理。如对一棵树的访问,传统的方法可以使用递归函数来处理,下面是对树的一个中序遍历的示例:

例1:

def deal_tree(node):
    if not node:
        return
    if node.leftnode:
        deal_tree(node.leftnode)
    process(node)
    if node.rightnode:
        deal_tree(node.rightnode)

deal_tree(root)

可以看出,对结点的处理函数与递归函数是混在一起的,不是很清晰。使用Iterator的方式改写后为:

例2:

1    def walk_tree(node):
2        if not node:
3            return
4        if node.leftnode:
5            for i in walk_tree(node.leftnode):
6                yield i
7        yield node
8        if node.rightnode:
9            for i in walk_tree(node.rightnode):
10               yield i
11
12   for node in wald_tree(root):
13       process(node)

生成结点的过程仍然是一个递归过程,但对于返回后的结点的处理就变成了线性化的处理,结构上要清晰多了。第5-6,9-10行要特别注意,如果不这样处理直接调用walk_tree的话,其实返回的是一个Iterator对象,而不是想要的元素。

象上面的walk_tree函数在 Python 中可以叫作Generator–产生器,它的作用是生成一个Iterator的对象。那么它主要是将一个函数过程进行封装,转化为Iterator对象,每执行到yield语句时,函数的状态,数据都保存起来,然后返回相应的值。取下一个值的时候,再从上次运行的地方继续运行,如果遇上yield语句,则再次保存状态,返回结果,如果不存在值了,则自动引发一个异常StopIteration,从而Iterator不再产生新的值。从此处我们可以了解,这里的Iterator只可以遍历一次,但并非所有的都是这样,你完全可以对其进行控制。

下面我再介绍一下如何构造自已的Iterator。很简单,创建一个类,满足Iterator的协议,也就是要定义__iter__方法,它返回一个Iterator对象,这个对象必须有next方法,因此我们可以总结出两种对象模式:

class A:
    def __iter__(self):
        return self

    def next(self):
        if has_next_value(self):
            return next_value
        else:
            raise StopIteration

class B:
    def __iter__(self):
        return iterator_obj

A,B分别为两种对象模式(都是示例代码)。模式A表示,在A中定义了next方法,因此__iter__简单地返回自身即可。当不存在下一个值时,引发StopIteration异常。模式B表示,它使用了其它的Iterator对象,因此只需要定义__iter__即可,next不需要定义,因为返回的Iterator对象已经含有next方法了。如果是自已实现next方法,那么在返回值之前需要记住当前的状态,以便下一次运行时,可以取下一个值。

第2个例子好象与这里讲的不一样啊。这就是前面讲的Generator,它的作用就是把一个函数转换成一个Iterator,它自动保存状态,中间数据,引发异常,全部是自动化了。而且它只可以遍历一次。如果想再次遍历,只有重新生成新的Iterator对象才可以。

在最新的 Python 2.4 版中新增了Genetaor Expression方式,它是用来生成简单的,在函数调用需要序列参数时的一种Iterator写法,语法就象是list comprehension的格式,如:

>>> sum(i*i for i in range(10))                 # sum of squares
285

不过这种写法必须要在小括号对中,因此它的使用是有限的。它的目的主要是想更好的使用内存。

前面我们提到不是所有的Iterator只可以遍历一次(使用Generator生成的只能遍历一次),你完全可以控制它重新遍历。比如我们可以在Iterator对象中增加一个复位方法,用来将内部的计数恢复到开始状态,这样我们就可以重新遍历了。

下面我们总结一下:

Iterator对象:具有__iter__方法,和next方法。当没有新值时引发StopIteration异常。

Iterator的好处:在某些情况下可以使程序结构清晰,如将递归等非线性处理转为线性处理。可以减少内存的占用。

Generator:将一个函数转化成Iterator对象的方法。使用它只需要在函数中需要返回值的时候调用yield语句。它是生成Iterator对象的简单方法,只适用于函数。

<think>好的,我现在需要回答用户关于Python中生成器(generator迭代器(iterator)的区别联系的问题。首先,我得回顾一下自己对这些概念的理解,确保正确性。 首先,迭代器(Iterator)是Python中用于迭代的对象,遵循迭代器协议,即必须实现__iter__()__next__()方法。每次调用next()时会返回下一个值,直到没有元素时引发StopIteration异常。例如,列表、元组等可迭代对象可以通过iter()函数转换为迭代器。 生成器(Generator)则是一种特殊的迭代器,使用yield语句来生成值。生成器函数在每次调用next()时执行到yield处暂停,保存当前状态,下次继续执行。生成器表达式也是一种创建生成器的方式,类似列表推导式,但使用圆括号。生成器更节省内存,因为它们是惰性求值的,不需要一次性生成所有数据。 接下来,我需要整理它们的区别联系。区别方面,生成器是迭代器的一种,但实现方式更简洁,使用yield。生成器只能遍历一次,而迭代器可能支持多次遍历(取决于具体实现)。内存占用上,生成器更高效,尤其处理大数据时。语法上,生成器用函数yield,或者生成器表达式,而迭代器需要定义类并实现__next____iter__方法。 联系方面,两者都用于迭代,都遵循迭代器协议。生成器属于迭代器的子类,所以生成器也是迭代器。使用时都可以通过for循环或next()函数处理。 然后,我需要检查用户提供的引用资料,确保回答符合引用内容。例如,引用[3]提到iter()函数用于从序列生成迭代器,引用[4]说明生成器是另一种迭代器形式。这些需要整合到回答中,正确标注引用。 可能还需要考虑用户可能混淆的点,比如生成器普通迭代器的创建方式不同,或者生成器的惰性求值特性。同时,提供代码示例帮助理解,如生成器函数生成器表达式的例子,以及自定义迭代器的类示例。 最后,要确保回答结构清晰,分点列出区别联系,使用中文,LaTeX格式正确,引用标识正确放置。然后生成相关问题,可能涉及应用场景、性能比较、创建方式等。</think>### Python生成器迭代器的区别及联系 #### 1. **迭代器(Iterator)** - **定义**:迭代器是遵循**迭代器协议**的对象,需实现两个核心方法: - `__iter__()`:返回迭代器自身 - `__next__()`:返回下一个元素,若没有则抛出`StopIteration`异常 例如,使用`iter()`可将列表转为迭代器: ```python lst = [1, 2, 3] it = iter(lst) # 转换为迭代器 print(next(it)) # 输出: 1 [^3] ``` - **特点**: - 支持手动或循环遍历(如`for`循环) - 部分迭代器可重复使用(如文件对象),部分只能遍历一次(如生成器) #### 2. **生成器(Generator)** - **定义**:生成器是**通过函数生成值的迭代器**,使用`yield`关键字暂停执行并保留状态: ```python def count_down(n): while n > 0: yield n n -= 1 gen = count_down(3) # 生成器对象 print(next(gen)) # 输出: 3 [^4] ``` 或通过生成器表达式创建: ```python gen_expr = (x**2 for x in range(3)) # 生成器表达式 ``` - **特点**: - **惰性求值**:按需生成值,节省内存 - **一次性遍历**:遍历结束后无法重启 - **简洁语法**:无需显式定义`__iter__``__next__`方法 #### 3. **区别对比** | **特性** | 迭代器 | 生成器 | |-------------------|---------------------------|--------------------------------| | **实现方式** | 需定义类并实现协议方法 | 使用`yield`或生成器表达式 | | **内存占用** | 可能占用较多(存储所有数据) | 惰性计算,内存效率高 | | **复用性** | 部分可复用(如列表迭代器) | 只能遍历一次 | | **语法复杂度** | 较高 | 较低(自动生成协议方法) | #### 4. **联系** - **共同协议**:两者均遵循迭代器协议,可通过`next()`获取值 - **包含关系**:生成器是迭代器的子类(所有生成器都是迭代器,反之不成立) - **应用场景**:均用于处理大规模数据流或需要延迟计算的场景[^2] #### 5. **代码示例对比** - **自定义迭代器**: ```python class Squares: def __init__(self, n): self.n = n self.current = 0 def __iter__(self): return self def __next__(self): if self.current >= self.n: raise StopIteration result = self.current ** 2 self.current += 1 return result it = Squares(3) print(list(it)) # 输出: [0, 1, 4] ``` - **生成器实现相同功能**: ```python def squares_gen(n): current = 0 while current < n: yield current ** 2 current += 1 gen = squares_gen(3) print(list(gen)) # 输出: [0, 1, 4] ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值