我是靠谱客的博主 开朗眼睛,最近开发中收集的这篇文章主要介绍python 迭代器和生成器迭代器和生成器参考,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

迭代器和生成器

迭代器和生成器的基本概念

  • 迭代器

    迭代器(Iterator)是同时实现__iter__() 与 __next__()方法的对象。

  • 生成器

    Python 中,提供了两种 生成器(Generator) ,一种是生成器函数,另一种是生成器表达式

    • 生成器函数:包含yeild的函数称为生成器函数
    • 生成器表达式:与列表推导式类似,区别是使用()进行包裹 例:(i for i in range(10))

迭代器(Iterator)

可迭代对象

可迭代对象,可以简单理解为可遍历对象,即能够使用 for循环遍历的对象。Python中常见的可迭代对象有:

  1. 一类是集合数据类型和迭代器,如listtupledictsetstr 和实现了__next__方法的类对象
  2. 一类是generator,包括生成器和带yield的generator function。

对于Python中的任意对象,只要它定义了可以返回一个迭代器的 __iter__ 方法,或者定义了可以支持下标索引的 __getitem__ 方法,那么它就是一个可迭代对象。对可迭代对象使用 __iter__ 方法后,会返回一个迭代器。

我们只需要使用 isinstance(object, Iterable)即可判断给定的 object是否为可迭代对象。

from collections.abc import Iterable

isinstance([1, 2, 3], Iterable)  # True
isinstance((1, 2, 3), Iterable)  # True
isinstance('123', Iterable)  # True
isinstance({1, 2, 3}, Iterable)  # True
isinstance(range(3), Iterable)  # True
isinstance({'key': 'value'}, Iterable)  # True
isinstance(123, Iterable)  # False

严格来讲,isinstance() 只会将有 iter 方法的对象判断为 Iterable。换言之,仅用 getitem 方法实现的可迭代对象会被 isinstance() 误判为不可迭代对象。最正确的做法是直接尝试 iter(object),如果没有报错,则说明 object 是可迭代对象。

将可迭代对象转换成迭代器

我们可以使用iter()方法将现有的可迭代对象转化为可迭代器:

s = '12345'
myiter = iter(s)
myiter
# <str_iterator at 0x25e6f40d130>

不断调用 next()方法来依次获取迭代器的元素:

next(myiter)
# '1'
next(myiter)
# '2'
next(myiter)
# '3'
next(myiter)
# '4'
next(myiter)
# '5'
next(myiter)
# StopIteration:

可见迭代器执行到最后时会抛出一个 StopIteration异常。为避免这种异常,我们完全可以用更简单的 for循环去遍历:

for e in myiter:
    print(e)
# 1
# 2
# 3
# 4
# 5

构造迭代器

构造一个迭代器只需要在自定义的类中实现两个方法:__iter____**next__**

迭代器是一个可以记住遍历位置的对象。迭代器对象会从第一个元素开始访问,直到所有元素都被访问为止,且只能前进不能后退。当我们构造类时,必须要有一个名为 __**init**()__的函数,该函数可以在实例化时进行一些初始化。__**iter**()__ 方法的行为类似,可以执行操作(初始化等),但必须始终返回迭代器对象本身。__**next**()__方法还允许你进行其他操作,并且必须返回序列中的下一项。

class MyIter:
    def __iter__(self):
        self.count = 1
        return self
    
    def __next__(self):
        x = self.count
        self.count += 1
        return x

我们创建了一个返回数字的迭代器,每次序列的数值都将 +1

myiter = iter(MyIter())
next(myiter)
# 1
next(myiter)
# 2
next(myiter)
# 3

如果我们一直调用 next()的方法,则序列的值将会无限递增下去。即如果我们使用 for循环去遍历上述迭代器,循环将永远进行下去。

myiter = iter(MyIter())
for e in myiter:
    print(e)
# 循环将一直进行下去...

为了防止迭代永远进行下去,我们可以在迭代次数达到一定值时抛出 StopIteration异常。

class MyIter:
    def __iter__(self):
        self.count = 1
        return self
    
    def __next__(self):
        if self.count <= 5:
            x = self.count
            self.count += 1
            return x
        else:
            raise StopIteration

这样再执行 for循环就不会一直进行下去了:

myiter = iter(MyIter())
for e in myiter:
    print(e)
# 1
# 2
# 3
# 4
# 5

生成器 (Generator)

在Python中,一边迭代(循环)一边计算的机制,称为生成器。生成器能够迭代的关键是因为它有一个 __next__方法。

为什么要有生成器呢?我们知道,列表中的所有数据都存储在内存中,如果有海量数据的话将会非常消耗内存。很多时候,我们只需要访问列表中前面的元素,这样一来后面的元素所占用的空间就白白浪费了。

如果列表元素能够按照某种算法推算出来,那我们就可以在循环的过程中不断推算出后续的元素,这样就不必创建完整的列表,从而节省了大量的空间(即用多少就生成多少)。

有以下两种常用方法来创建生成器:

  • 将列表解析式中的 [] 改为()
  • 在自定义的函数中使用 yield 关键字。此时这个函数就不再是一个普通函数,而是一个生成器,调用该函数就是创建了一个生成器对象。

使用()构造生成器

比较以下两段代码:

'''列表'''
a = [x for x in range(3)]
type(a)
# list

'''生成器'''
a = (x for x in range(3))
type(a)
# generator

可以对生成器使用 next()方法:

next(a)
# 0
next(a)
# 1
next(a)
# 2
next(a)
# StopIteration:

但一般我们不会用 next()来获取下一个返回值,而是直接使用 for循环来迭代。

for i in a:
	print(i)

使用带yield关键词的函数构造生成器

带有 yield的函数不再是一个普通函数,而是一个生成器。yield相当于return一个值,并且记住这个返回的位置,下次迭代时,代码从 yield下一条语句
开始执行。

  • 例子
def foo():
    print("starting...")
    while True:
        res = yield 4
        print("res:",res)
g = foo()
print(next(g))
print("*"*20)
print(next(g))
  • 输出
starting...
4
********************
res: None
4
  1. 程序开始执行以后,因为foo函数中有yield关键字,所以foo函数并不会真的执行,而是先得到一个生成器g(相当于一个对象)
  2. 直到调用next方法,foo函数正式开始执行,先执行foo函数中的print方法,然后进入while循环
  3. 程序遇到yield关键字,然后把yield想想成return,return了一个4之后,程序停止,并没有执行赋值给res操作,此时next(g)语句执行完成,所以输出的前两行(第一个是while上面的print的结果,第二个是return出的结果)是执行print(next(g))的结果,
  4. 程序执行print("*"20),输出20个
  5. 又开始执行下面的print(next(g)),这个时候和上面那个差不多,不过不同的是,这个时候是从刚才那个next程序停止的地方开始执行的,也就是要执行res的赋值操作,这时候要注意,这个时候赋值操作的右边是没有值的(因为刚才那个是return出去了,并没有给赋值操作的左边传参数),所以这个时候res赋值是None,所以接着下面的输出就是res:None,
  6. 程序会继续在while里执行,

参考

python中yield的用法详解–最简单,最清晰的解释_冯爽朗的博客-CSDN博客_python yield

Python中的迭代器与生成器_Lareges的博客-CSDN博客_python的迭代器和生成器

python中生成器与迭代器到底有什么区别?一文带你彻底搞清楚

最后

以上就是开朗眼睛为你收集整理的python 迭代器和生成器迭代器和生成器参考的全部内容,希望文章能够帮你解决python 迭代器和生成器迭代器和生成器参考所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(56)

评论列表共有 0 条评论

立即
投稿
返回
顶部