zoukankan      html  css  js  c++  java
  • python(迭代器,生成器)

    1.迭代

      将某个数据集中的数据‘一个一个挨着取出来’,就是迭代。

    1 '''
    2 dir([1,2].__iter__())是列表迭代器中实现的所有方法,dir([1,2])是列表中实现的所有方法,都是以列表的形式返回给我们的,为了看的更清楚,我们分别把他们转换成集合,
    3 然后取差集。
    4 '''
    5 #print(dir([1,2].__iter__()))
    6 #print(dir([1,2]))
    7 print(set(dir([1,2].__iter__()))-set(dir([1,2])))

     运行结果:{'__length_hint__', '__setstate__', '__next__'}

     其中 __length_hint__表示的是迭代元素的个数。

     __next()__表示取出元素

     __setstate__设置迭代起始的位置

     1 iter_l = [1,2,3,4,5,6].__iter__()
     2 # 获取迭代器中元素的长度
     3 print(iter_l.__length_hint__())
     4 # 根据索引值指定从哪里开始迭代
     5 print('*',iter_l.__setstate__(4))
     6 #一个一个的取值
     7 print('**',iter_l.__next__())
     8 print('***',iter_l.__next__())
     9 # 如果再次__next__()会直接报错
    10 print('****',iter_l.__next__())
    11 # 报错 停止迭代 StopIteration

    使用try except处理这个异常

    1 # 使用异常处理机制处理这个机制
    2 list_1 = [1,2,3,4,5,6]
    3 iterator = list_1.__iter__()
    4 while 1:
    5     try:
    6         item = iterator.__next__()
    7         print(item)
    8     except StopIteration:
    9         break

    迭代器遵循迭代器协议:必须拥有__iter__方法和__next__方法

    对range()进行如下测试:

    1 print('__iter__' in dir(range(12))) # True
    2 print('__next__' in dir(range(12))) # False
    3 from collections import Iterator
    4 from collections import Iterable
    5 print(isinstance(range(2),Iterator)) # False 不是一个迭代器 迭代器必须同时满足__iter__ __next__
    6 print(isinstance(range(2),Iterable)) # True 是一个迭代对象 __iter__ 

    可迭代协议 

     可以被迭代的满足的要求就叫做可迭代协议。可迭代协议的定义非常的简单。就是在内部实现了__iter__方法。

     分析__iter__方法做了什么事情呢?

    1 print([1,2,3].__iter__()) # <list_iterator object at 0x10ae1a2e8>
    2 print(range(2).__iter__()) # <range_iterator object at 0x10aeef6f0>

    随后就可以快乐的使用for in i xxx 就可以迭代取出内部的数据咯

    1 i = range(2).__iter__() # <range_iterator object at 0x10aeef6f0>
    2 for j in i:
    3     print(j) # 0 i

    2.生成器

      2.1 生成器函数

      一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。

     1 def generator():
     2     print(1)
     3     yield 'a'
     4     print(2)
     5     yield 'b'
     6 g = generator()
     7 # print(g) # <generator object generator at 0x110419f10>
     8 # print(g.__next__())
     9 """
    10 1
    11 a
    12 """
    13 # print(g.__next__())
    14 """
    15 1
    16 a
    17 2
    18 b
    19 """
    20 # print(g.__next__()) # 没有了报错。.StopIteration
    21 # 当前 使用for 迭代取出
    22 for i in g:
    23     print(i)
    24 """
    25 1
    26 a
    27 2
    28 b
    29 """

    生成器有什么好处呢?就是不会一下子在内存中生成太多数据。

    假设要生产200w箱娃哈哈. 按需生产。请求一箱。生产一箱。

     1 # 200w箱娃哈哈 需要一箱。生产一箱
     2 import time
     3 def create_wahaha():
     4     for i in range(1,2000000):
     5         yield'生产了%s箱娃哈哈'%i
     6 
     7 generator = create_wahaha()
     8 # 开始要第一箱娃哈哈
     9 for i in range(100):
    10     if i == 10:
    11         break
    12     print(generator.__next__())
    13     time.sleep(1)
    14 
    15 
    16 print(generator.__next__()) # 生产了11箱娃哈哈 并不会从第一箱开始.除非再次调用create_wahaha()
    17 
    18 
    19 generator2 = create_wahaha()
    20 print(generator2.__next__()) # 生产了1箱娃哈哈

     2.2、send

     1 def generator():
     2     print(123)
     3     content = yield 1
     4     print('=====',content)
     5     print(456)
     6     yield 2
     7 g = generator()
     8 ret = g.__next__()
     9 print("*****",ret) 
    10 ret = g.send('hello')
    11 print('*******',ret)
    12 """
    13 123
    14 ***** 1
    15 ===== hello
    16 456
    17 ******* 2
    18 """
    19 # 使用send获取下一个值的效果和next基本一致
    20 # 只是在获取下一个值的时候,给上一个yield的位置传递一个数据
    21 # --------
    22 # 第一次使用生成器的时候,必须使用next获取下一个值
    23 # 最后一个yield不能接收外部的值
    send

    小试牛刀,借助yield计算移动的平均速度

     1 def average():
     2     total = 0
     3     count = 0
     4     avg = None
     5     while True:
     6       term = yield avg
     7       total += term
     8       count +=1
     9       avg = total / count
    10 a = average()
    11 # next(a)
    12 a.__next__()
    13 print(a.send(10))
    14 print(a.send(20))
    15 print(a.send(30))
    使用send计算平均速度

    进一步借助装饰器去掉每一次调用必须执行next()

     1 def init(func): #在调用被装饰生成器函数的时候首先用next激活生成器
     2     def inner(*agrs,**kwargs):
     3         g = func(*agrs,**kwargs)
     4         next(g)
     5         return g
     6     return inner
     7 
     8 @init
     9 def average():
    10     total = 0.0
    11     count = 0
    12     average = None
    13     while True:
    14         term = yield average
    15         total += term
    16         count += 1
    17         average = total / count
    18 g_avg = average()
    19 # next(g_avg) 在装饰器中已经执行了该方法
    20 print(g_avg.send(10))
    21 print(g_avg.send(20))
    带装饰器简化send
  • 相关阅读:
    一道小学数学题
    Ubuntu下使用git提交代码至GitHub
    C#几个小知识点
    C#中巧用#if DEBUG 进行调试
    使用 HPC Pack 为 Azure 中的 Windows HPC 工作负荷创建和管理群集的选项
    使用 Chef 自动执行 Azure 虚拟机部署
    在 Azure 中管理 Windows 虚拟机的可用性
    什么是 Azure 中的虚拟机规模集?
    从 Azure 下载 Windows VHD
    如何使用 Packer 在 Azure 中创建 Windows 虚拟机映像
  • 原文地址:https://www.cnblogs.com/shine-rainbow/p/9775824.html
Copyright © 2011-2022 走看看