python基础笔记

2018/05/05 python

可迭代对象/迭代器/生成器

字典、序列(包括字符串、列表和元组)、迭代器(iterator)、生成器(generator)都是可迭代对象

  • 定义可迭代对象必须实现__iter__()方法
  • 定义迭代器必须实现__iter__()和__next__()方法
  • __iter__方法返回迭代器类实例,__next__方法返回迭代的每一步结果,实现该方法时,超出边界要抛出StopIteration异常

    可迭代对象与迭代器的具体例子:

      class MyList(object):            # 定义可迭代对象类
        
          def __init__(self, num):
              self.data = num          # 上边界
         
          def __iter__(self):
              return MyListIterator(self.data)  # 返回该可迭代对象的迭代器类的实例
         
         
      class MyListIterator(object):    # 定义迭代器类,其是MyList可迭代对象的迭代器类
         
          def __init__(self, data):
              self.data = data         # 上边界
              self.now = 0             # 当前迭代值,初始为0
         
          def __iter__(self):
              return self              # 返回该对象的迭代器类的实例;因为自己就是迭代器,所以返回self
         
          def __next__(self):              # 迭代器类必须实现的方法
              while self.now < self.data:
                  self.now += 1
                  return self.now - 1  # 返回当前迭代值
              raise StopIteration      # 超出上边界,抛出异常
         
         
      my_list = MyList(5)              # 得到一个可迭代对象
      print(type(my_list))             # 返回该对象的类型
         
      my_list_iter = iter(my_list)     # 得到该对象的迭代器实例(iter用于创建迭代器。iter()直接调用对象的__iter__(),并把__iter__()的返回结果作为自己的返回值;next(iterator/generator)输出迭代器的下一个元素,迭代器只能往前不能往后,生成器可通过send往后)
      print(type(my_list_iter)) 
         
      for i in my_list:                # python解释器会在第一次迭代时自动调用iter(obj),之后的迭代会调用迭代器的__next__()方法,for语句会自动处理最后抛出的StopIteration异常
          print(i) 
    

    输出

      <class '__main__.MyList'>
      <class '__main__.MyListIterator'>
      0
      1
      2
      3
      4
    
  • 生成器是一种特殊的迭代器,生成器通过yield关键字自动实现了迭代器协议(即__iter__()和__next__()方法),不需要手动实现两个方法
  • yield可以理解为return,返回后面的值给调用者。不同的是return返回后,函数会被释放,而生成器则不会。 在直接调用next方法或用for语句进行下一次迭代时,生成器会从yield下一句开始执行,直至遇到下一个yield
  • 生成器在迭代过程中可通过send改变当前的迭代值

    生成器的具体例子:

      def myList(num):      # 定义生成器
          now = 0           # 当前迭代值,初始为0
          while now < num:
              val = (yield now)                      # 返回当前迭代值,并接受通过send重新设置当前迭代值
              now = now + 1 if val is None else val  # val为None,迭代值自增1,否则重新设定当前迭代值为val
         
      my_list = myList(5)   # 得到一个生成器对象
         
      print(type(my_list))    
      print(next(my_list))   # 返回当前迭代值
      print(next(my_list)) 
         
      my_list.send(0)       # 重新设定当前的迭代值 往后跳跃
      print(next(my_list)) 
        
      my_list.send(3)       # 重新设定当前的迭代值 往前跳跃
      print(next(my_list)) 
         
      print(dir(my_list))     # 返回该对象所拥有的方法名,可以看到__iter__与__next__在其中 
    

    输出

      <class 'generator'>
      0
      1
      1
      4
      ['__class__', '__del__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__name__', '__ne__', '__new__', '__next__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'gi_yieldfrom', 'send', 'throw']
    

参考

Search

    Post Directory