编程语言
首页 > 编程语言> > 【python】迭代器和生成器

【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]

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

可迭代的归约函数

 

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