zoukankan      html  css  js  c++  java
  • 迭代器和生成器

    迭代器

    可迭代对象:

      字符串、列表、元组、字典、集合都可以被for循环,说明他们都是可迭代的。

    两种方式证明可迭代对象:

    # 1 - 使用方法看对象有没有__iter__() 方法
    ls = [1,2,3]
    print(dir(ls)) #使用dir() 查看对象都有什么方法
    
    # 2 - 使用模块
    from collections import Iterable
    # isinstance()判断哪个对象是什么类型
    print(isinstance(ls,Iterable)) # True

    可迭代协议

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

    总结:

      可以被for循环的都是可迭代的。

      可迭代的:内部必须含有一个__iter__方法

    迭代器(iterator)

    l = [1,2,3,4]
    l_iter = l.__iter__() #将可迭代的转化为迭代器
    item = l_iter.__next__() #取出第一个值
    print(item) # 1
    item = l_iter.__next__() #取出第二个值
    print(item) # 2

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

    for 循环内部:

      将可迭代对象转化为迭代器(可迭代对象.__iter__())

      内部使用__next__()方法,依次取值

      加了异常处理功能,取值到底后自动停止。

    用while循环模拟for循环:

    # 用while循环模拟for循环
    l = [1,2,3,4]
    i_iter = l.__iter__()
    while True:
        try:
            item = i_iter.__next__()
            print(item)
        except StopIteration:
            break

    总结:

      for 循环就是基于迭代器协议提供了一个统一的可遍历所有对象的方法,即在遍历之前,先调用对象的__iter__方法将其转成一个迭代器,然后使用迭代器协议去实现循环访问,这样所有的对象就可以通过for循环来遍历了。

      最重要的一点,转化成迭代器,在循环时,同一时刻在内存中只出现一条数据,极大限度的节省了内存。

    生成器

    初始生成器(Generator)

      我们知道的迭代器有两种:一种是调用方法直接返回的,一种是可迭代对象通过执行iter方法得到的,迭代器有的好处就是可以节省内存。

      如果在某些情况下,需要自己写,我们自己写的这个能实现迭代器功能的东西就叫生成器。

    本质:迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现)

    特点:惰性运算,开发者自定义

    Python中提供的生成器:

      1、生成器函数:常规函数定义,但是,使用yield返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行。

      2、生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表。

    生成器函数

      一个包含yield关键字的函数就是一个生成器函数。

      yield可以为我们从函数中返回值,

      调用生成器函数不会得到返回的具体的值,而是一个可迭代对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值,指导函数执行结束。

    #生成器函数
    def gene_func():
        yield 1
        yield 2
        yield 3
    # print(gene_func()) # 不会执行函数 得到一个可迭代对象 <generator object gene_func at 0x1040fbba0>
    ge_object = gene_func()
    a = ge_object.__next__()
    print(a) # 1
    print(next(ge_object)) # 2

    生成器:不会在内存中一下子生成太多数据。要多少就执行多少__next__()

    Send方法

    send()方法在获取下一个值的时候,给上一个yield的位置传递一个参数

    def gene_func():
        send_fc1 = yield 1
        print('send_fc1 : %s'%send_fc1) #赋值
        yield 2
    ge_obj = gene_func()
    ret = ge_obj.__next__() # 1
    print('第一个yield返回的值:%s'%ret)
    ret1 = ge_obj.send('赋值') # 2
    print('send赋值:%s'%ret1)

      send获取下一个值的效果和next基本一致,只是在获取下一个值得时候,给上一个yield的位置传递一个数据。

    注意:

      第一次使用生成器的时候,因为没有上一个yield,用next获取下一个值

      最后一个yield不能接受外部的值。

    def add(n, a_i):
        return n + 1
    
    def test():
        for r_i in range(4):
            yield r_i
    
    g = test()
    for n in [1,10]:
        g = (add(n, i) for i in g) #
    
    # 第一次: g = ((add(n,i),add(n,i),add(n,i),add(n,i)) 没有调用,不执行 n不赋值
    # 第二次:g = (add(n,add(n,i)),add(n,add(n,i)),add(n,add(n,i)),add(n,add(n,i)))
    
    print(list(g))
    
    '''
    每个生成器只能取一次 只能前进不能后退
    生成器在不找他要值得时候始终不执行
    当他执行的时候,要以执行时候的所有变量为准
    '''
  • 相关阅读:
    Jmeter在命令行运行技巧
    Tomcat6 一些调优设置内存和连接数
    用例结构优化心得
    LoadRunner 调用dll方法
    DLL接口自动化测试总结
    Loadrunner进行md5加密方法
    Loadrunner检查点使用总结
    网络上可供测试的Web Service
    04 json,xml混合封装通信
    03 xml封装通信接口
  • 原文地址:https://www.cnblogs.com/liangying666/p/9202050.html
Copyright © 2011-2022 走看看