zoukankan      html  css  js  c++  java
  • python notice9 迭代器和生产器

    一、迭代器

      可以进行for循环的都是可迭代对象,常见的可迭代对象:str、list、tuple、dict、set、range、f(文件),它们都遵循可迭代协议。  

    s = "小黑人"
    for el in s:
        print(el)

      Iterable:可迭代对象,内部包含__iter__()函数。

      Iterator:迭代器,内部包含__iter__同时还包含__next__()。

      想要查看某数据类型是否为可迭代对象或者迭代器,可以通过dir()函数查看时候包含__iter__或者__iter__和__next()__。

      通过__iter__()可以获取到对象的迭代器,使用迭代器中的__next__()来获取迭代器中的元素。

    s = "小黑人"
    c = s.__iter__()    #获取迭代器
    print(c.__next__())    #使用迭代器进行迭代,获取一个元素,小
    print(c.__next__())    #
    print(c.__next__())    #
    print(c.__next__())    #StopIteration

      迭代器特点:

        1.节省内存。

        2.惰性机制。

        3.只能向下执行,不能反复。

    补充:for循环机制

    s = "小黑人"
    c = s.__iter__()
    while True:
        try:
            i = c.__next__()
            print(i)
        except StopIteration:
            break

     二、生成器

      生成器实质就是迭代器。获取生成器有三种方法:生成器函数、推导式获取生成器、通过数据转换获取生成器。

    1.生成器函数

    def func():
        print("小黑人")
        yield 114    #把函数中return改成yield,这个函数就是生成器函数
        print("小黑人不黑")
        yield 3114    #原来时0114,但是会报错,0不能打头,语法不支持。
    ret = func()
    print(ret)
    ss = ret.__next__()
    print(ss)
    ss = ret.__next__()
    print(ss)
    结果:<generator object func at 0x0000027203D4A2A0>
            小黑人
            114
         小黑人不黑
         3114

      注:执行这个函数时,就不是函数的执行,而是获取这个生成器。生成器本质时迭代器,可以通过__next__()来执行生成器。

      yield和return效果一样,遇到return是直接停止执行函数,而yield是分段来执行一个函数(当内容多时,一次性全部输出,会占大量内存;而用yield时,next一此就输出一个,不占内存)。当程序运行完最后一个yield,后面继续进行__next__()时程序会报错。

      生成器也可以用for循环获取内部元素。因为生成器就是迭代器,迭代器为可迭代对象,故可以进行for循环。 

    补充send:

      1.send()和__next__()一样,都可以让生成器执行到下一个yield;

      2.send可以给上一个yield的位置传递值,但不能给最后一个yield传值,同时在第一次执行生成器代码时不能使用send()。

    def func():
        print("小黑人")
        a = yield 114    #把函数中return改成yield,这个函数就是生成器函数
        print("a=",a)
        yield 3114    #原来时0114,但是会报错,0不能打头,语法不支持。
    ret = func()
    ss = ret.__next__()
    print(ss)
    ss = ret.send("小黑人不黑")
    print(ss)
    
    结果:
    小黑人
    114
    a= 小黑人不黑
    3114

     2.生成器表达式

      列表、字典、集合都有推导式,元组没有推导式。

      列表推导式:[结果 fof 变量 in 可迭代对象 if 筛选]

      字典推导式:{结果 fof 变量 in 可迭代对象 if 筛选}  结果:key:value

      集合推导式:{结果 fof 变量 in 可迭代对象 if 筛选}  结果:key

      eg:列表推导式:list = [结果 for in 可迭代对象 if 条件]

    lst = ["小黑人%s" % i for i in range3)]
    print(lst)
    结果:
    ['小黑人0', '小黑人1', '小黑人2']

      列表推导式代码简单,但是出现错误之后不易排查。

      生成器表达式和列表推导式语法一样,只是把[]换成()。

    lst =("小黑人%s" % i for i in range(0))
    print(lst)
    结果:
    <generator object <genexpr> at 0x0000017602B9A2A0>

      生成器表达式和列表推导式区别:

        1.列表推导式比较耗内存,一次性加载,生成器表达式几乎不占内存,使用时才分配和使用内存。

        2.得到的值不一样。列表推导式得到的是一个列表,生成器表达式获取的是一个生成器。

      注:生成器有惰性机制:生成器只有在方位的时候才有值。说白了,找它要才会给值,不找它要,它是不会执行的。

    def func():
        print(111)
        yield 222
    
    g = func()    #生成器g
    g1 = (for i in g)    #生成器g1,但是g1的数据来源于g
    g2 = for i in g1)    #生成器g2,但是g2的数据来源于g1
    
    print(list(g))    #获取g中的数据,这时func()才会被执行,打印111,获取222,g完毕
    print(list(g1))    #获取g1中的数据,g1的数据来源是g,但g已经取完,没有数据了。
    print(list(g2))    #和g1相同

    测试题

    def add(a,b):
        return a + b
    
    def test():
        for r_i in range(4):
            yield r_i
    
    g = test()
    
    for n in [2,10]:
        g = (add(n,i) for i in g)  
    '''
    展开一层:g = (add(n,i) for i in add(n,i) for i in g),
    展开第二层:g = (add(n,i) for i in add(n,i) for i in test()),
    两个n在取值时不可能不同,取值时为10。
    '''
    
    print(g)
    print(list(g))    #惰性机制,不到最后不会拿值。
        
    结果:
    <generator object <genexpr> at 0x000001C5C0C6A408>
    [20, 21, 22, 23]

      

      

  • 相关阅读:
    黑马程序员——指针的应用
    黑马程序员——C语言基础常量、运算符、函数
    黑马程序员——数组
    黑马程序员——循环结构for,while,do..while
    webView去掉右侧导航条
    使用Eclipse构建Maven的SpringMVC项目
    win7 自动登录
    eclipse 自动提示
    apache+php+mysql 环境配置
    KMP子串查找算法
  • 原文地址:https://www.cnblogs.com/xiaolu-fan/p/11240423.html
Copyright © 2011-2022 走看看