zoukankan      html  css  js  c++  java
  • Python(10):Python迭代器与生成器(iterator、for循环、generator、yield)

    一、迭代器(foreach)

    1、可迭代的对象

    内置有__iter__方法的都叫可迭代的对象。

    Python内置str、list、tuple、dict、set、file都是可迭代对象

    x = 1.__iter__  # SyntaxError: invalid syntax
    
    # 以下都是可迭代的对象
    name = 'nick'.__iter__
    print(type(name))  # <class 'method-wrapper'>

    2、迭代器对象

    执行可迭代对象的__iter__方法,拿到的返回值就是迭代器对象

    只有字符串和列表都是依赖索引取值的,而其他的可迭代对象都是无法依赖索引取值的,只能使用迭代器对象。

    1. 内置有__iter__方法,执行该方法会拿到迭代器本身。
    2. 内置__next__方法,执行该方法会拿到迭代器对象中的一个值。
    s = 'hello'
    iter_s = s.__iter__()
    print(type(iter_s))  # <class 'str_iterator'> iter_s为迭代器对象

    while True:
        try:
            print(iter_s.__next__())
        except StopIteration:
            break
    #hello

    3、迭代器有两个基本的方法:iter()next()

    s = 'hello'
    iter_s = iter(s) # 创建迭代器对象
    print(type(iter_s))  # <class 'str_iterator'> iter_s为迭代器对象
    
    while True:
        try:
            print(next(iter_s)) # 输出迭代器的下一个元素
    
        except StopIteration:
            break
    # hello

    4、for迭代器循环

    可迭代对象可以直接使用常规for语句进行遍历

    for循环称为迭代器循环,in后必须是可迭代的对象。

    #str
    name = 'nick' 
    for x in name:
        print(x)
    
    #list
    for x in [None, 3, 4.5, "foo", lambda: "moo", object, object()]:
        print("{0}  ({1})".format(x, type(x)))
    
    #dict
    d = {
        '1': 'tasty',
        '2': 'the best',
        '3 sprouts': 'evil',
        '4': 'pretty good'
    }
    
    for sKey in d:
        print("{0} are {1}".format(sKey, d[sKey]))
    
    #file
    f = open('32.txt', 'r', encoding='utf-8')
    for x in f:
        print(x)
    f.close()

    5、实现迭代器(__next__和__iter__)

    把一个类作为一个迭代器使用需要在类中实现两个方法 __iter__() 与 __next__() 。

    • __iter__() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成。
    • __next__() 方法会返回下一个迭代器对象。
    • StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 __next__() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。

    创建一个返回数字的迭代器,初始值为 1,逐步递增 1,在 20 次迭代后停止执行:

    class MyNumbers:
      def __iter__(self):
        self.a = 1
        return self
     
      def __next__(self):
        if self.a <= 20:
          x = self.a
          self.a += 1
          return x
        else:
          raise StopIteration
     
    myclass = MyNumbers()
    myiter = iter(myclass)
     
    for x in myiter:
      print(x)

    1、模拟range

    class Range:
        def __init__(self, n, stop, step):
            self.n = n
            self.stop = stop
            self.step = step
    
        def __next__(self):
            if self.n >= self.stop:
                raise StopIteration
            x = self.n
            self.n += self.step
            return x
    
        def __iter__(self):
            return self
    
    
    for i in Range(1, 7, 3):
        print(i)
    
    #1
    #4

    2、斐波那契数列

    class Fib:
        def __init__(self):
            self._a = 0
            self._b = 1
    
        def __iter__(self):
            return self
    
        def __next__(self):
            self._a, self._b = self._b, self._a + self._b
            return self._a
    
    
    f1 = Fib()
    for i in f1:
        if i > 100:
            break
        print('%s ' % i, end='')
    
    # 1 1 2 3 5 8 13 21 34 55 89

    二、生成器

    1、yield

    在 Python 中,使用了 yield 的函数被称为生成器(generator)。

    跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器

    在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。

    调用一个生成器函数,返回的是一个迭代器对象。

    yield后面可以加多个数值(可以是任意类型),但返回的值是元组类型的。

    1. 提供一种自定义迭代器的方式
    2. yield可以暂停住函数,并提供当前的返回值
    import sys
    
    
    def fibonacci(n):  # 函数 - 斐波那契
        a, b, counter = 0, 1, 0
        while True:
            if counter > n:
                return
            yield a
            a, b = b, a + b
            counter += 1
    
    
    f = fibonacci(10)  #f 是一个生成器
    print(type(f))  # <class 'generator'>
    
    while True:
        try:
            print(next(f), end=" ")
        except StopIteration:
            sys.exit()

      yield和return:

      1. 相同点:两者都是在函数内部使用,都可以返回值,并且返回值没有类型和个数的限制
      2. 不同点:return只能返回一次值;yield可以返回多次值

      2、自定义range()方法

      def my_range(start, stop, step=1):
          while start < stop:
              yield start
              start += 1
      
      
      g = my_range(0, 3)
      print(f"list(g): {list(g)}")

      复杂版本:

      def range(*args, **kwargs):
          if not kwargs:
              if len(args) == 1:
                  count = 0
                  while count < args[0]:
                      yield count
                      count += 1
              if len(args) == 2:
                  start, stop = args
                  while start < stop:
                      yield start
                      start += 1
              if len(args) == 3:
                  start, stop, step = args
                  while start < stop:
                      yield start
                      start += step
      
          else:
              step = 1
      
              if len(args) == 1:
                  start = args[0]
              if len(args) == 2:
                  start, stop = args
      
              for k, v in kwargs.items():
                  if k not in ['start', 'step', 'stop']:
                      raise ('参数名错误')
      
                  if k == 'start':
                      start = v
                  elif k == 'stop':
                      stop = v
                  elif k == 'step':
                      step = v
      
              while start < stop:
                  yield start
                  start += step
      
      
      for i in range(3):
          print(i)  # 0,1,2
      
      for i in range(99, 101):
          print(i)  # 99,100
      
      for i in range(1, 10, 3):
          print(i)  # 1,4,7
      
      for i in range(1, step=2, stop=5):
          print(i)  # 1,3
      
      for i in range(1, 10, step=2):
          print(i)  # 1,3,5,7,9

      3、生成器表达式(i.for .in)

      把列表推导式的[]换成()就是生成器表达式 。

      优点:比起列表推导式,可以省内存,一次只产生一个值在内存中

      t = (i for i in range(10))
      print(t)  # <generator object <genexpr> at 0x00000000026907B0>
      print(next(t))  # 0
      print(next(t))  # 1

      举例:

      with open('32.txt', 'r', encoding='utf8') as f:
          nums = [len(line) for line in f]  # 列表推导式相当于直接给你一筐蛋
      
      print(max(nums))  # 2
      
      
      with open('32.txt', 'r', encoding='utf8') as f:
          nums = (len(line) for line in f)  # 生成器表达式相当于给你一只老母鸡。
      
      print(max(nums))  # ValueError: I/O operation on closed file.
    1. 相关阅读:
      HDU 5528 Count a * b 欧拉函数
      HDU 5534 Partial Tree 完全背包
      HDU 5536 Chip Factory Trie
      HDU 5510 Bazinga KMP
      HDU 4821 String 字符串哈希
      HDU 4814 Golden Radio Base 模拟
      LA 6538 Dinner Coming Soon DP
      HDU 4781 Assignment For Princess 构造
      LA 7056 Colorful Toy Polya定理
      LA 6540 Fibonacci Tree
    2. 原文地址:https://www.cnblogs.com/springsnow/p/12053195.html
    Copyright © 2011-2022 走看看