• Python笔记4(迭代器和生成器)


    一、迭代器

    如何从列表、字典中取值的:
    1)index索引 ,key,前提必须知道索引或key值才能取到对应的value
    2)for循环
    凡是可以使用for循环取值的都是可迭代的
    可迭代协议 :内部含有__iter__方法的都是可迭代的
    迭代器协议 :内部含有__iter__方法和__next__方法的都是迭代器

     1 print(dir([1,2,3]))
     2 #>>>['__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']
     3 lst_iter = [1,2,3].__iter__()
     4 print(lst_iter.__next__())#>>>1
     5 print(lst_iter.__next__())#>>>2
     6 print(lst_iter.__next__())#>>>3
     7 
     8 #上面代码相当于for循环取值
     9 for i in [1,2,3]:   #  使用for循环时,在内部调用__iter__方法,变成迭代器。[1,2,3].__iter__()
    10     print(i)
    11 
    12 #使用while循环实现for循环的机制
    13 l = [1,2,3]
    14 lst_iter = iter(l)   # iter(l)相当于l.__iter__(),都是产生一个迭代器
    15 while True:
    16     try:
    17         print(next(lst_iter)) # next(lst_iter)相当于lst_iter.__next__()
    18     except StopIteration:
    19         break
    20 
    21 # 什么是可迭代的
    22 # 什么是迭代器     迭代器 = iter(可迭代的),自带一个__next__方法
    23 # 可迭代 最大的优势 节省内存
    24 
    25 #例:以下是python3运行的结果
    26 from collections import Iterable,Iterator
    27 print(range(100000000))
    28 print(isinstance(range(100000000),Iterable))#判断是不是可迭代的
    29 print(isinstance(range(100000000),Iterator))#判断是不是迭代器
    30 # >>>range(0, 100000000)
    31 # >>>True
    32 # >>>False
    33 
    34 # python2 range 不管range多少 会生成一个列表 这个列表将用来存储所有的值
    35 # python3 range 不管range多少 都不会实际的生成任何一个值
    36 # 迭代器的优势:
    37 #     节省内存
    38 #     取一个值就能进行接下来的计算 ,而不需要等到所有的值都计算出来才开始接下来的运算 —— 快
    39 # 迭代器的特性:惰性运算
    40 
    41 #
    42 f = open()
    43 for line in f:#用一行读一行
    44 
    45 # 可迭代对象:列表 字典 元组 字符串 集合 range 文件句柄 enumerate(加序号)

     二、生成器

    生成器 Generator
    自己写的迭代器 就是一个生成器
    两种自己写生成器(迭代器)的机制:生成器函数   生成器表达式

    1、生成器函数

     1 # 凡是带有yield的函数就是一个生成器函数
     2 def func():
     3     print('****')
     4     yield 1
     5     print('^^^^')
     6     yield 2   # 记录当前所在的位置,等待下一次next来触发函数的状态
     7 
     8 g = func()
     9 print('--',next(g))
    10 #>>>****
    11 #>>>-- 1
    12 print('--',next(g))
    13 #>>>^^^^
    14 #>>>-- 2

    例1:

    # 需要定制200 0000件衣服
    # 承包:牛翔  一起做完200 0000才进行反馈,这时候已经开到40期了
    # 承包:赵英杰 200 0000,你每一期需要的时候才进行生产和反馈
    
    def cloth(num):
        ret = []
        for i in range(num):
            ret.append('cloth%s'%i)
        return ret
    ret=cloth(10)
    print(ret)#>>>['cloth0', 'cloth1', 'cloth2', 'cloth3', 'cloth4', 'cloth5', 'cloth6', 'cloth7', 'cloth8', 'cloth9']
    
    # 想要生成器函数执行,需要用next
    def cloth_g(num):
        for i in range(num):
            yield 'cloth%s'%i
    
    g = cloth_g(1000)
    print(next(g))#>>>cloth0
    print(next(g))#>>>cloth1
    print(next(g))#>>>cloth2

    例2:使用生成器监听文件输入的例子

     1 #在mac系统上不能直接操作文件,需要关闭或使用程序写入文件
     2 import time
     3 def listen_file():
     4     with open('userinfo') as f:
     5         while True:
     6             line = f.readline()
     7             if line.strip():
     8                 yield line.strip()
     9             time.sleep(0.1)
    10 
    11 g = listen_file()
    12 for line in g:
    13     print(line)

    例3:send关键字

     1 def func():
     2     print(11111)
     3     ret1 = yield 1
     4     print(22222,'ret1 :',ret1)
     5     ret2 = yield 2
     6     print(33333,'ret2 :',ret2)
     7     yield 3
     8 
     9 g = func()
    10 ret = next(g)#第一次使用生成器时不能用send执行
    11 print(ret)
    12 #>>>11111
    13 #>>>1
    14 print(g.send('alex'))  # 在执行next的过程中 传递一个参数 给生成器函数的内部
    15 #>>>22222 ret1 : alex
    16 #>>>2
    17 print(g.send('金老板'))
    18 #>>>33333 ret2 : 金老板
    19 #>>>3

    备注:向生成器中传递值 有一个激活的过程 第一次必须要用next触发这个生成器

    例4:计算移动平均值

     1 # 计算移动平均值
     2 # 月度 的 天平均收入
     3 def average():
     4     sum_money = 0
     5     day = 0
     6     avg = 0
     7     while True:
     8         money = yield avg
     9         sum_money += money
    10         day += 1
    11         avg = sum_money/day
    12 
    13 g = average()
    14 next(g)#得到一个0
    15 print(g.send(200))#>>>200.0
    16 print(g.send(300))#>>>250.0
    17 print(g.send(600))#>>>366.6666666666667

     2、预激生成器

    作用:当程序中的多个函数都需要预激活,那么就可以交给装饰器来解决

     1 def init(func):
     2     def inner(*args,**kwargs):
     3         ret = func(*args,**kwargs)
     4         next(ret)  # 预激活
     5         return ret
     6     return inner
     7 
     8 @init
     9 def average():
    10     sum_money = 0
    11     day = 0
    12     avg = 0
    13     while True:
    14         money = yield avg
    15         sum_money += money
    16         day += 1
    17         avg = sum_money/day
    18 
    19 g = average()
    20 print(g.send(200))
    21 print(g.send(300))
    22 print(g.send(600))

    3、yield from (python3中的用法)

     1 def generator_func():
     2     yield from range(5)
     3     yield from 'hello'
     4 #与下列代码相同
     5     # for i in range(5):
     6     #     yield i
     7     # for j in 'hello':
     8     #     yield j
     9 
    10 g = generator_func()
    11 for i in generator_func():#与for i in g:相同
    12     print(i)
    13 
    14 g = generator_func()
    15 while True:
    16     print(generator_func())#会报错,每一次执行此函数都会生成一个新的生成器
    17 g1 = generator_func()
    18 g2 = generator_func()
    19 next(generator_func())
    20 next(generator_func())

    4、如何从生成器中取值

    1 # 第一种 :next  随时都可以停止 最后一次会报错
    2 print(next(g))
    3 print(next(g))
    4 # 第二种 :for循环 从头到尾遍历一次 不遇到break、return不会停止
    5 for i in g:
    6     print(i)
    7 # 第三种 :list tuple 数据类型的强转  会把所有的数据都加载到内存里 非常的浪费内存
    8 print(g)
    9 print(list(g))

    5、总结

     1 # 生成器函数 是我们python程序员实现迭代器的一种手段
     2 # 主要特征是 在函数中 含有yield  不建议使用return
     3 # 调用一个生成器函数 不会执行这个函数中的带码 只是会获得一个生成器(迭代器)
     4 # 只有从生成器中取值的时候,才会执行函数内部的带码,且每获取一个数据才执行得到这个数据的带码
     5 # 获取数据的方式包括 next send 循环 数据类型的强制转化
     6 # yield返回值的简便方法,如果本身就是循环一个可迭代的,且要把可迭代数据中的每一个元素都返回 可以用yield from
     7 # 使用send的时候,在生成器创造出来之后需要进行预激,这一步可以使用装饰器完成
     8 # 生成器的特点 : 节省内存 惰性运算
     9 # 生成器用来解决 内存问题 和程序功能之间的解耦
    10 #解耦:将功能性的代码进行尽量拆分,提交代码可读性,复用性

    三、生成器表达式

     1 # 列表推倒式
     2 #求平方,然后存放到列表中
     3 #方式1
     4 new_lst = []
     5 for i in range(10):
     6     new_lst.append(i**2)
     7 print(new_lst)
     8 #方式2
     9 print([i**2 for i in range(10)])
    10 #求2的余数,然后存放放列表中
    11 l = [1,2,3,-5,6,20,-7]
    12 print([i%2 for i in range(10)])
    13 #找出所有的奇数,然后存放放列表中
    14 l = [1,2,3,-5,6,20,-7]
    15 print([num for num in l if num%2 == 1])
    16 
    17 # 30以内所有能被3整除的数
    18 print([i for i in range(30) if i%3 ==0])
    19 
    20 # 30以内所有能被3整除的数的平方
    21 print([i**2 for i in range(30) if i%3 ==0])
    22 
    23 # 找到嵌套列表中名字含有两个‘e’的所有名字
    24 names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
    25          ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
    26 print([name for name_lst in names for name in name_lst if name.count('e') == 2])
    27 
    28 # 生成器表达式
    29 l = [i for i in range(30) if i%3 ==0]   # 列表推倒式 排序的时候
    30 g = (i for i in range(30) if i%3 ==0)   # 生成器表达式 庞大数据量的时候 使用生成器表达式
    31 print(l)#>>>[0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
    32 print(g)#>>><generator object <genexpr> at 0x000002A16630B8E0>
    33 for i in g:print(i)

    四、面试题

     1 # 面试题1
     2 # def demo():
     3 #     for i in range(4):
     4 #         yield i
     5 #
     6 # g=demo()
     7 #
     8 # g1=(i for i in g)
     9 # g2=(i for i in g1)
    10 #
    11 # print(list(g1))#>>>[0, 1, 2, 3]
    12 # print(list(g2))#>>>[]
    13 
    14 
    15 # 面试题2
    16 # def add(n,i):
    17 #     return n+i
    18 #
    19 #
    20 # def test():
    21 #     for i in range(4):
    22 #         yield i
    23 #
    24 # g=test()
    25 # for n in [1,10]:
    26 #     g=(add(n,i) for i in g)
    27 #
    28 # print(list(g))#>>>[20, 21, 22, 23]
    29 
    30 
    31 # 一个生成器 只能取一次
    32 # 生成器在不找它要值的时候始终不执行
    33 # 当他执行的时候,要以执行时候的所有变量值为准
  • 相关阅读:
    第四次作业--个人作业--软件案例分析
    第五次作业--团队项目--需求规格说明书
    Beta版本的贡献率
    软工实践总结
    beta版本冲刺第四天
    beta版本冲刺第三天
    beta版本冲刺第一天
    Beta版本冲刺计划及安排
    团队项目冲刺总结
    项目冲刺第六天
  • 原文地址:https://www.cnblogs.com/xingye-mdd/p/8955909.html
Copyright © 2020-2023  润新知