终于搞懂了Python的可迭代对象、迭代器和生成器

前言

  在学习Python语言,不可避免遇到各种绕口的概念,比如可迭代对象、迭代器和生成器,新手看了第一印象就是一脸懵。为此,本文详细介绍和解释这些概念,让新手一看就会。
  回顾Python中的数据存储结构,Python是用容器来存储数据,比如:list、dict、tuple、strset…等等,当数据量不大的时候用这些存储没什么问题,当数据量特别大甚至是无限的时候,就不能使用这些容器来存储了,于是Python有一种机制专门解决这种问题。

一、可迭代对象(iterable)和迭代器(iterator)

1.1 概念介绍

  通俗点讲,可迭代对象就是可以产生迭代器的对象,所谓迭代器就像一个懒加载的工厂,本身不存储数据,只有你向它索要的时候临时给你生成数据。下面用一个例子来解释:

>>> x = [1, 2, 3]
>>> y = iter(x)
>>> z = iter(x)
>>> next(y)
1
>>> next(y)
2
>>> next(z)
1
>>> type(x)
<class 'list'>
>>> type(y)
<class 'list_iterator'>

  在这个例子中,x是一个list对象,是一个可迭代对象,通过iter()函数生成x的迭代器y,那么只有在调用next()方法时y才输出数据。了解了两者的基本内容,下面来深入讲解。
  先抛出可迭代对象和迭代器的结论:

  1. 可迭代对象包含迭代器; 如果一个对象拥有__iter__方法,其是可迭代对象;
  2. 如果一个对象拥有next方法,其是迭代器;
  3. 定义可迭代对象,必须实现__iter__方法;定义迭代器,必须实现__iter__和__next__方法。

  这三个结论看起来很绕,来解释一下,可迭代对象是一个对象,对象包含__iter__方法,我们可以使用iter()函数来生成该对象的迭代器,生成的迭代器包含__iter__和__next__方法。迭代器也有__iter__,说明迭代器也是可迭代对象,当对迭代器使用iter()函数时,返回的是该迭代器本身,而next方法不断地获取迭代器中的下一个元素,如果迭代器中没有更多元素了,则抛出StopIteration异常。

1.2 为什么要用迭代器

  我们通过可迭代对象生成迭代器,那我们要用迭代器的目的是什么呢?开头讲了,迭代器的使用是为了节省空间,想象一下,通过列表生成式,我们可以直接创建一个列表,但是,受到内存限制,列表容量肯定是有限的,而且创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。通过例子加深印象:
  生成无限序列:

>>> from itertools import count
>>> counter = count(start=13)
>>> next(counter)
13
>>> next(counter)
14

  从一个有限序列中生成无限序列:

>>> from itertools import cycle
>>> colors = cycle(['red', 'white', 'blue'])
>>> next(colors)
'red'
>>> next(colors)
'white'
>>> next(colors)
'blue'
>>> next(colors)
'red'

  从无限的序列中生成有限序列:

>>> from itertools import islice
>>> colors = cycle(['red', 'white', 'blue'])  # infinite
>>> limited = islice(colors, 0, 4)            # finite
>>> for x in limited:                         
...     print(x)
red
white
blue
red

1.3 定义一个迭代器

  为了进一步加深迭代器概念理解,我们建立一个生成斐波那契数列的迭代器:

class Fib:
    def __init__(self):
        self.prev = 0
        self.curr = 1

    def __iter__(self):
        return self

    def __next__(self):
        value = self.curr
        self.curr += self.prev
        self.prev = value
        return value

>>> f = Fib()
>>> print(next(f))
1
>>> print(next(f))
1
>>> print(next(f))
2
>>> print(next(f))
3

  Fib既是一个可迭代对象(因为它实现了__iter__方法),又是一个迭代器(因为实现了__iter__和__next__方法)。实例变量prev和curr用户维护迭代器内部的状态。每次调用next()方法的时候做两件事:

  1. 为当前这次调用生成返回结果
  2. 为下一次调用next()方法修改状态

  迭代器就像一个懒加载的工厂,等到有人需要的时候才给它生成值返回,没调用的时候就处于休眠状态等待下一次调用。

二、生成器(generator)

  生成器其实是一种特殊的迭代器,不过这种迭代器更加优雅。它不需要再像上面的类一样写__iter__()和__next__()方法了,只需要一个yiled关键字。 生成器一定是迭代器(反之不成立),因此任何生成器也是以一种懒加载的模式生成值。

2.1 用生成器来实现斐波那契数列:

def fib():
	print("Start...")
    prev, curr = 0, 1
    while True:
        yield curr
        prev, curr = curr, curr + prev

>>> f = fib()
>>> print(type(f))
<class 'generator'>

>>> print(next(f))
Start...
1
>>> print(next(f))
1
>>> print(next(f))
2
>>> print(next(f))
3

  来解释一下流程:

  1. 程序开始执行以后,因为fib函数中有yield关键字,所以fib函数并不会真的执行,而是先得到一个生成器f(相当于一个对象);
  2. 直到第一次调用next方法,fib函数正式开始执行,先执行fib函数中的print和prev, curr = 0, 1,然后进入while循环,程序遇到yield关键字,然后把yield想想成return,return了一个curr之后,程序停止,并没有执行函数后面的代码;
  3. 又开始执行下面的print(next(f)),这个时候和上面那个差不多,不过不同的是,这个时候是从刚才那个next程序停止的地方开始执行的,也就是要执行prev, curr = curr, curr + prev,然后循环又遇到yield,return变量curr后程序又停止。

  到这里你可能就明白yield了,带yield的函数是一个生成器,而不是一个函数了,这个生成器有一个函数就是next函数,next就相当于“下一步”生成哪个数,这一次的next开始的地方是接着上一次的next停止的地方执行的,所以调用next的时候,生成器并不会从fib函数的开始执行,只是接着上一步停止的地方开始,然后遇到yield后,return出要生成的数,此步就结束。

2.2 Send()方法

def fun():
    print("starting...")
    while True:
        res = yield 4
        print("res:",res)
>>> f = fun()
>>> print(next(f))
starting...
4
>>> print(f.send(23))
res:23
4

  来解释一下流程:

  1. f = fun()因为fun函数里面有yield关键字,所以函数不会执行并且返回一个生成器;
  2. 第一次执行next()方法,开始执行fun函数,直到遇到yield,抛出yield后面的对象,程序停止;
  3. 程序执行f.send(23),程序会从上次停止的地方开始执行,因为send了一个23,所以上次停止的地方出现一个23,由于send方法中包含next()方法,所以程序会继续向下运行执行,res赋值为23,执行print,然后再次进入while循环,遇到yield,抛出yield后面的对象,程序停止;

三、总结

  迭代器持有一个内部状态的字段,用于记录下次迭代返回值,它实现了__next__和__iter__方法,迭代器不会一次性把所有元素加载到内存,而是需要的时候才生成返回结果。
  生成器是一种特殊的迭代器,它的返回值不是通过return而是用yield。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值