【python】迭代器和生成器

生成器和迭代器

概念

生成器:凭空生成元素,例如range()函数,之前返回完整的列表,现在返回类似生成器的对象

迭代器:从集合中取出元素,惰性获取数据项,按需一次获取一个

所有的生成器都是迭代器,因为生成器完全实现了迭代器接口。

所有的序列都可迭代

解释器需要迭代对象x时,会自动调用iter(x):

  1. 检查对象是否实现了__iter__方法,如果实现了就调用它,获取一个迭代器

  2. 如果没有实现__iter__方法,但是实现了__getitem__方法,python会创建一个迭代器,尝试按顺序获取元素

  3. 如果尝试失败,则抛出TypeError异常

只要对象实现了__iter__方法,则isinstance(x, abc.Iterable)为True,因为abc.Iterable 类实现了 __subclasshook__ 方法。但由于以上所说序列的特殊性,所以判断对象是否可迭代,最准确的方式是调用iter(x)函数。

 

可迭代的对象与迭代器的区别

Python 从可迭代的对象中获取迭代器。

示例1

s = 'abc'
for char in s:
  print(char)

如果没有for,可以怎么写呢?

s = 'abc'
it = iter(s)
while True:
  try:
      print((next(it)))
  except StopIteration:
      del it
      break

这样写呢?

s ='abc'
print(next(s))
# TypeError: 'str' object is not an iterator

结论:

不要在可迭代对象里实现next方法,尝试把可迭代对象变成迭代器是错误的,也是常见的反模式。我们必须在对象的__iter__方法中去新建一个独立的迭代器,在这个迭代器中去实现__next__方法。可迭代的对象一定不能是自身的迭代器,不可以实现__next__方法。

标准的迭代器接口有两个方法:

__next__:返回下一个可用的元素,如果没有元素了,抛出StopIteration异常

__iter__:返回self

image-20220310144221143

实现迭代器

  1. Iterable.__iter__ 方法中返回一个 Iterator 实例。具体的 Iterator 类必须实现 __next__方法,返回单个元素,此外还要实现Iterator.__iter__方法,返回实例本身。具体见示例14-4。即如果对象实现了能返回迭代器的__iter__方法,那么对象是可迭代的对象,python从可迭代的对象中获取迭代器。

  2. 使用yield关键字创建生成器函数。生成器函数调用时会构建一个实现了迭代器的生成器对象。只要函数中有关键字yield,则该函数是生成器函数

    1. def gen_AB():
        print('start')
        yield 'a'
        print('end')

      for i in gen_AB():
        print(i)
      # 注释掉函数中的yield,则会报错TypeError: 'NoneType' object is not iterable
    2. 其它

  3. 使用()生成器表达式,()只是一个语法糖,代替yield生成器函数来创建生成器,更节省内存

    1. def gen_AB():
        print('start')
        yield 'a'
        print('end')

      res1 = [x * 3 for x in gen_AB()]
      for i in res1:
        print('--->', i)
      # start
      # end
      # ---> aaa

      res2 = (x * 3 for x in gen_AB()) # res2 是一个生成器对象,只有 for 循环迭代 res2 时,gen_AB 函数的定义体才会真正执行
      for i in res2:
        print('--->', i)
      # start
      # ---> aaa
      # end
    2. 其它

  4. 使用现成的函数,比如要生成等差数列

    1. class ArithmeticPregression:
        def __init__(self, begin, step, end=None):
            self.begin = begin
            self.end = end
            self.step = step

        def __iter__(self): # 属于方法二
            result = type(self.begin + self.step)(self.begin)
            forever = self.end is None
            index = 0
            while forever or result < self.end:
                yield result
                index += 1
                result = self.begin + self.step * index
    2. # 使用itertools.count和takewhile
      import itertools

      def aritprog_gen(begin, step, end=None):
        first = type(begin + step)(begin)
        ap_gen = itertools.count(first, step)
        if end is not None:
            ap_gen = itertools.takewhile(lambda n: n < end, ap_gen)
        return ap_gen

      # 用法
      gen = itertools.count(1, .5)
      print(next(gen)) # 1
      print(next(gen)) # 1.5

      gen = itertools.takewhile(lambda n: n < 3, itertools.count(1, .5))
      print(list(gen)) # [1, 1.5, 2.0, 2.5]

标准库中的生成器函数整理

  • 用于过滤的生成器函数

    • compress

    • dropwhile

    • filter(内置)

    • filterfalse

    • isslice

    • takewhile

  • 用于映射的生成器函数

    • accumulate

    • enumerate(内置)

    • map(内置)

    • starmap

  • 用于合并多个可迭代对象的生成器函数

    • chain

    • chain.from_iterable

    • product

    • zip(内置)

    • zip_longest

  • 用于把输入的各个元素扩展成多个多个输出元素的生成器函数

    • combinations

    • combinations_with_replacement

    • count

    • cycle

    • permutations

    • repeat

  • 用于重新排列元素的生成器函数

    • groupby

    • reversed(内置)

    • tee

可迭代的归约函数

  • all

    • # 一旦确定结果则立即停止迭代器
      g = (n for n in [0, 0.0, 7, 8])
      all(g)
      print(next(g)) # 0.0
    •  

  • any

    • g = (n for n in [0, 0.0, 7, 8])
      any(g)
      print(next(g)) # 8
    •  

  • max

  • min

  • functools.reduce

  • sum

  •  

 

posted @   小笼包2022  阅读(114)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示