ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

【python】迭代器和生成器

2022-04-07 10:33:22  阅读:196  来源: 互联网

标签:__ 迭代 python self 生成器 print gen


生成器和迭代器

概念

生成器:凭空生成元素,例如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

  •  

 

标签:__,迭代,python,self,生成器,print,gen
来源: https://www.cnblogs.com/xiaolongbao2021/p/16111040.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有