迭代器,生成器函数和各种推导式

一.迭代器

  • 一个数据类型中包含了__iter__函数表示这个数据是可迭代的
  • 特征:

    1. 省内存
    2. 惰性机制
    3. 只能向前. 不能后退

  • 作用:统一了各种数据类型的遍历
  • dir(数据类型): 

    dir() 可以帮我们查看xxx数据能够执行的操作

例如

print(dir(str)) # 有__iter__,是可迭代对象

print(dir(int)) # 没有__iter__,不是可迭代对象

print(dir(list)) # 有__iter__,是可迭代对象

print(dir(dict)) # 有__iter__,是可迭代对象

print(dir(bool)) # 没有__iter__,不是可迭代对象
# 共性:所有带有__iter__的东西都可以进行for循环, 带有__iter__的东西就是可迭代对象

  

  • 判断迭代器和可迭代对象的方案(野路子)

    __iter__ 可迭代的

    __iter__     __next__ 迭代器

  • 判断迭代器和可迭代对象的方案(官方)

    from collections import Iterable, Iterator

    isinstance(对象, Iterable) 是否是可迭代的

    isinstance(对象, Iterator) 是否是迭代器

 

#借助于两个模块 Iterator迭代器, Iterable可迭代的
from collections import Iterable, Iterator
lst = [1,2,3]
print(lst.__next__())
print(isinstance(lst, Iterable)) # xxx是否是xxx类型的. True
print(isinstance(lst, Iterator)) # xxx是否是xxx迭代器. False


it = lst.__iter__()  # 迭代器一定可迭代,  可迭代的东西不一定是迭代器
print(isinstance(it, Iterable)) # xxx是否是xxx类型的. True
print(isinstance(it, Iterator)) #  xxx是否是xxx迭代器. True

 

  • 迭代器一定可迭代,  可迭代的东西不一定是迭代器
  • 模拟for循环
# 模拟for循环 for el in lst:
lst=[1,2,3] it = lst.__iter__() # 获取到迭代器 while 1: # 循环 try: # 尝试 el = it.__next__() # 那数据 print(el) except StopIteration: # 出了错误, 意味着数据拿完了 break # 结束循环

  

 

二.生成器定义与获取

  •   定义:生成器实质就是迭代器.
  • 在python中有三种方式来获取生成器:
    1.  通过生成器函数
    2. 通过各种推导式来实现生成器
    3. 通过数据的转换也可以获取生成器
def func():
    print("我叫周润发")
    yield "林志玲"   # yield表示返回. 不会终止函数的执行
ret = func() # 执行函数, 此时没有运行函数. 此时我们拿到的是生成器
 print("返回值是", ret) # <generator生成器 object func at 0x0000000009E573B8>
# 执行到下一个yield
print(ret.__next__()) # 第一次执行__next__此时函数才开始执行
print(ret.__next__()) # 执行到下一个yield
print(ret.__next__()) # StopIteration
  • 我们可以看到, yield和return的效果是一样的. 有什么区别呢? 

        yield是分段来执行一个函数. return是直接停止执行函数.

  • 生成器函数在执行的时候返回生成器. 而不是直接执行此函数
  • 能向下执行的两个条件:

      __next__(), 执行到下一个yield      
   send(), 执行到下一个yield, 给上一个yield位置传值
def func():
    print("韭菜盒子")
    a = yield "韭菜鸡蛋"
    print("a", a)
    b = yield "韭菜西红柿"
    print("b", b)
    c = yield "火烧"
    print("c", c)
gen = func()#获取生成器
print(gen.__next__()) # 执行到第一个yield
print(gen.send("篮球")) # 给上一个yield位置传值,即给a一个值'篮球'
print(gen.send("足球")) # 给上一个yield位置传值,即给b一个值'足球'
  • 所有的生成器都是迭代器都可以直接使用for循环
  • 都可以使用list()函数来获取到生成器内所有的数据

 

  • 生成器中记录的是代码而不是函数的运行

    def func():
        print("值 1")
        yield "值2"
    gen= func()#获取生成器
  • gen = func() # 创建生成器. 此时运行会把生成器函数中的代码记录在内存
  • 当执行到__next__(), 运行此空间中的代码, 运行到yield结束.
  • 优点: 节省内存, 生成器本身就是代码. 几乎不占用内存
  • 特点: 惰性机制, 只能向前. 不能反复

三.生成器表达式

  (结果 for循环 if...)

 

g =(i for i in range(10))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(iter(g))

 

四.各种推导式 

  • 列表推导式 [结果 for循环 if...]
lst = [i for i in range(1, 19)]
print(lst)
  • 字典推导式 {结果(k:v) for循环 if...}
  • 集合推导式 {结果(k) for循环 if...}

  元组没有推导式,小括号括起来的是生成器表达式

补充:yield from

def func():
lst = ["衣服%s" % i for i in range(500)] yield from lst # 可以把一个可迭代对象分别进行yield返回
lst1 = ["python%s" % i for i in range(18)] yield from lst1 gen = func() print(gen.__next__()) print(gen.__next__())
lst全部返回完后才会返回lst1,不会交叉返回

 

lst = ["衣服%s" % i for i in range(500)]
   yield from lst
这个就相当于
for i in range(500):
    yield "衣服%s" % i

 

  

 

posted @ 2018-12-11 17:21  QV  阅读(221)  评论(0编辑  收藏  举报