Python之 解读 迭代器、生成器

一、迭代器
  • 1.list、str、tuple、dict等数据类型,可以使用for...in... 循环语句进行遍历,并依次返回数据。这样的我们称它是可迭代对象
  • 2.可迭代对象的本质:
    • 1.当我们使用for…in… 进行每一次迭代时,都会依次返回一个数据直至没有数据,结束。那在这个过程中,会有这么一个“人”去给我们记录这次获取哪个数据,下次又要获取哪个数据,那这个帮我们记录数据的“人”,称为迭代器
    • 2.iter(): 可迭代对象是通过__iter__方法向我们提供一个迭代器,也就是指向提供的那个迭代器。当我们遍历时,我们是通过 iter() 函数 获取该可迭代对象里的迭代器,然后对这个迭代器不断使用 next() 方法,进行返回数据。【注:当我们迭代完最后一个数据之后,再次调用next() 会抛出StopIteration的异常,来告诉我们已经没有数据了,不需要再使用 next() 函数】
    • 3.next(): 看上面所说的,那是不是定义一个 **next()**方法 的就是迭代器了?答案是否的,因为在Python中要求,迭代器本身也是可迭代的,所以还要在迭代器中实现__iter__方法。迭代器里面定义__iter__方法,难道又要提供一个新的迭代器?不是的,我们知道它本身就是一个迭代器,所以在__iter__方法中,只要返回自身就好了。

【总结】

  • 1.实现了iter方法的对象一定是可迭代对象,但不一定是一个迭代器。
  • 2.同时实现了iter方法next方法的对象,就一定是一个迭代器。
  • 3.看下面的代码,大致的执行流程就是,我们调用一个自定义的可迭代对象MyList(),通过__iter__方法获取一个MyIterator()迭代器,再通过迭代器下的__next__方法,返回数据。
  • 4.所以说 for item in Iterable 循环的本质就是先通过iter()函数获取可迭代对象Iterable的迭代器,然后对获取到的迭代器不断调用next()方法来获取下一个值并将其赋值给item,当遇到StopIteration的异常后循环结束。
from collections import Iterable, Iterator


# 自定义的一个可迭代对象
class MyList(object):
    def __init__(self):
        self.items = []  # 最后添加完数据的列表为:[1, 2, 3, 4, 5]

    def add(self, val):
        self.items.append(val)

    def __iter__(self):
        myiterator = MyIterator(self)
        return myiterator


# 自定义的供上面可迭代对象使用的一个迭代器
class MyIterator(object):
    def __init__(self, mylist):
        self.mylist = mylist
        # current用来记录当前访问到的位置,也就是索引
        self.current = 0

    def __next__(self):
        # 获取可迭代对象的长度
        if self.current < len(self.mylist.items):
            item = self.mylist.items[self.current]
            self.current += 1
            return item
        else:
            raise StopIteration

    def __iter__(self):
        return self


if __name__ == '__main__':
    mylist = MyList()
    # 先添加数据
    mylist.add(1)
    mylist.add(2)
    mylist.add(3)
    mylist.add(4)
    mylist.add(5)
    # 先通过 __iter__ 获取一个迭代器
    ret = mylist.__iter__()
    # 再通过迭代器中的 __next__() 拿到每一个数据;
    # 直到报:StopIteration 错误,停止 __next__。
    while True:
        try:
            print(ret.__next__())
        except StopIteration:
            print('已遍历完毕!')
            break

    # 这也就是for循环大致的实现过程
    # for num in mylist:
    #     print(num)

    x = isinstance(mylist, Iterable)  # 判断该对象是否是可迭代对象,是:True;否:False
    y = isinstance(ret, Iterator)  # 判断该对象是否是迭代器,是:True;否:False
    print('是否是可迭代对象:', x, '\n是否是迭代器:', y)

【扩展】

  • 1.dir():dir(数据),返回该数据可以执行的所有操作。

  • 2.导入:from collections import Iterable, Iterator

    • isinstance(对象, Iterable) # 判断该对象是否是可迭代对象,是:True;否:False
    • isinstance(对象, Iterator) # 判断该对象是否是迭代器,是:True;否:False
二、生成器
  • 其生成器的本质就是一个迭代器

  • 创建一个生成器:

    • 第一种,通过生成器表达式来获取生成器

       ( x for x in range(5))  # 注意;误区:没有元组推导式,这叫生成器表达式
      
    • 第二种,生成器函数

      # 只要在函数中,存在yield,那么该函数就是一个生成器函数;
      # 注意,生成器函数运行之后,产生一个生成器,而不是运行该函数
      def function():
          print('这是一个生成器函数')
          yield '没错,答对咯!'
          # yield 表示返回和return的作用差不多
          # 但不会向return那样返回时,终止函数的执行,而是可以分段的执行一个函数
          print('打印我,打印我~')
          val = yield '不要着急,一个一个来~'
          # 注意,这里val如果没有被传值时,val是等于None;
          # 因为yield 会将'不要着急,一个一个来~'进行返回,此时,val的值就为None,而不是'不要着急,一个一个来~'。
          print(f'来点不一样的...val + 1 = {val + 1}')
          yield '结束《《'
      
      
      # 注意,此时并没有运行函数
      gen = function()
      print(gen)  # 它是一个生成器
      ret1 = gen.__next__()  # 第一次执行 __next__ ,此时才开始运行该函数
      print(ret1)  # 注意,该返回值是 yield 返回的值
      ret2 = gen.__next__()  # 第二次执行 __next__, 将会接着上一次yeild的位置,进行往下运行。
      print(ret2)
      # send() : 可以给上一个yield的位置,进行传值。
      ret3 = gen.send(5)
      print(ret3)
      
      # 传统的使用return,将会一次性返回结果集,可能我们一时不需要这么多结果,这样就会浪费内存
      def function():
          lst = []
          for i in range(1, 1001):
              lst.append(i)
          return lst
      
      
      gen = function()
      print(gen)
      
      
      # 可以看出,同样的1000个量,此时,我们需要多少量,就拿多少量,这样就不会造成浪费内存了;
      # 总结:生成器、迭代器 最大的优点:节省内存空间
      def function1():
          for i in range(1, 1001):
              yield i
      
      
      gen1 = function1()
      print(gen1)
      print(gen1.__next__())
      print(gen1.__next__())
      print(gen1.__next__())
      print(gen1.__next__())
      
    • 第三种,类型转换

    🔨正在努力编辑中…

  • 总结:

    • 所有的生成器都是迭代器
    • 可以使用list()方法获取到生成器中的所有数据
    • 优点:节省内存空间;特点:惰性机制,只能向前,不能反复。

新手上路,代码写的不好,还请谅解,如果有理解错误的,也请大佬在评论区指出来,非常感谢!

以上就是迭代器、生成器的所有内容了,点赞收藏加评论是最大的支持哦!

📑编写不易,转载请注明出处,如有侵权,请联系我!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodeBoy‍

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值