python迭代器和生成器

迭代器

  首先说几个概念:

  1. 什么是可迭代对象(iterable)  :   顾名思义,可以返回一个迭代器的对象,也可以说能够在for循环中所使用的对象.如tuple,list,set等
  2. 什么是迭代器(iterator)         :   从一个集合序列中不断提取元素,直到没有元素可以返回,抛出异常.

 

    如何获取迭代器:

  通过可迭代对象的 __iter__方法来获取,

    

1 #coding = utf-8
2 lst = ["小明",["小李"],"小王","小刘"]  #lst是list类型,是可迭代对象
3 it = lst.__iter__()    #it就是迭代器

  如何判断是否为可迭代对象.

  

#coding = utf-8
content = dir(list)  
print(content)  #list中存在__iter__,是可迭代对象
'''
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
'''

  如何判断是迭代器还是可迭代对象.

  这里给出两种方法:

  (1) 通过dir()查看,同时存在__iter__和__next__方法的就是迭代器,只存在__iter__的就是可迭代对象.

print("__iter__"in dir(list))
print ("__next__"in dir(list))    #返回的是布尔值

  (2)通过python的collections

from collections import iterable
from collections import iterator

print (isinstance(lst,iterable))
print (isinstance(lst,iterator))
print (isinstance(lt,iterable))
print (isinstance(lt,iterator))

  迭代器的工作原理

  通过调用__next__函数,返回序列中下一个元素,直到取到最后一个抛出异常.StopIteration.

#coding = utf-8
lst = ["小明","小李","小王","小刘"]
it = lst.__iter__()
while 1:
        print(it.__next__())  #StopIteration

  迭代器的特点

  (1)只能返回下一个,不可逆向.

  (2)惰性机制,只有给予指令之后才会执行操作.

  (3)不占用内存.

   通过__next__方法模拟for循环.

lst = ["小明","小李","小王","小刘"]
it = lst.__iter__()
while 1:
     try:
         print(it.__next__())
     except StopIteration:    #抛出异常退出
         break

 

生成器

  生成器迭代器是较为容易混淆的两个概念.

  生成器: 返回的是一个迭代器对象的就是生成器 , 简单来说,加上yield的函数便构成了一个生成器.

  生成器的构造有以下几种方式:

    1,通过yield,普通的函数中包含yield就是生成器.

    2,通过生成器表达式

#coding = utf-8    
#通过添加yield
def func():
    yield 2
gen = func()
print(gen.__next__())    #2
#coding = utf-8
#通过推导式
gen = (i for i in range(0,3))
print(gen.__next__())    #0
print(gen.__next__())    #1
print(gen.__next__())    #2

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

  实际上next()send()在一定意义上作用是相似的,区别是send()可以传递yield表达式的值进去,而next()不能传递特定的值,只能传递None进去。因此,我们可以看做c.next() 和 c.send(None) 作用是一样的。

  例如

#codiing = utf-8
def func():
    yield 456
a = func()  #获取迭代器对象
print (a.__next__())    #456
a = func()    #惰性机制
print(a.send(none))    #456

  显而易见,两次打印结果相等.

 

 关于yield

  yield的作用和return相似,都具有有类似break特点,不同点是其中return是终止程序,而yield是等待下一次运行,分段进行函数.

#coding = utf-8
def func():
    return 1    #第一个return返回,第二个被终止 不再执行
    return 2    
ret = func()    
print(ret)    
#coding = utf-8
#1,2两个值都被返回
# def func():
#     yield 1    
#     yield 2
# gen = func()
# print(gen.__next__())    #1
# print(gen.__next__())    #2

 

 关于send()

  send()和__next__一样,都具有让生成器走向下一次的作用,但是send()具有向上一个yield传递值的作用,也正是由于这一特性,第一次执行生成器代码的时候,用__next__而不用send()

#coding =utf-8
def func():
    a = yield 1
    yield a
    yield 3
gen = func()
print(gen.__next__())
print(gen.send(5))    #send里的值赋值给上一个yield 导致a = 5
print(gen.send(gen))

   

 

原文地址:https://www.cnblogs.com/cuiyuanzhang/p/9468057.html