zoukankan      html  css  js  c++  java
  • what's the python之可迭代对象、迭代器与生成器(附面试题)

    可迭代对象

    字符串、列表、元祖、集合、字典都是可迭代的,数字是不可迭代的。(可以用for循环遍历取出内部元素的就是可迭代的)

    如何查看一个变量是否为可迭代:

    from collections import Iterable
                                 
    l = [1,2,3,4]                
    t = (1,2,3,4)                
    d = {1:2,3:4}                
    s = {1,2,3,4}                
                                 
    print(isinstance(l,Iterable))
    print(isinstance(t,Iterable))
    print(isinstance(d,Iterable))
    print(isinstance(s,Iterable))
    #结果为True就是可迭代,False就是不可迭代

    可以被迭代要满足的要求就叫做可迭代协议。可迭代协议的定义就是内部实现了__iter__方法,即可迭代对象中封装有__iter__方法。

     

    迭代器

    迭代器:用变量调__iter__后就可以生成一个迭代器,迭代器遵循迭代器协议:必须拥有__iter__方法和__next__方法。

    l = [1,2,3,4]
    l_iter = l.__iter__()#l_iter只是一个接受的变量
    item = l_iter.__next__()#利用迭代器取值
    print(item)#1
    item = l_iter.__next__()
    print(item)#2
    item = l_iter.__next__()
    print(item)#3
    item = l_iter.__next__()
    print(item)#4
    item = l_iter.__next__()
    print(item)#超出限度,报错

    上步在最后出现了报错情况,为了使程序不报错,可以在取完了的最后将其终止掉:

    l = [1,2,3,4]
    l_iter = l.__iter__()
    while True:
        try:
            item = l_iter.__next__()
            print(item)
        except StopIteration:
            break

     

     生成器

    生成器:(本质就是一个迭代器,不过是由程序员写出来的才叫生成器,内置的就叫迭代器)

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

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

     

    简易生成器:

    import time
    def func():
        a = 1
        print('现在定义了a变量')
        yield a
        b = 2
        print('现在又定义了b变量')
        yield b
    
    g1 = func()
    print('g1 : ',g1)       #打印g1可以发现g1就是一个生成器
    print('-'*20)   #我是华丽的分割线
    print(next(g1))
    time.sleep(1)   #sleep一秒看清执行过程
    print(next(g1))#每print一次next才会出来一个yield的值,不然就挂在上一个yield上不继续执行

    生成器有什么好处呢?就是不会一下子在内存中生成太多数据,只有在你要的时候才会给你你要的数据

    生成器应用的几个小栗子:

    有关衣服订单:

    def produce():
        """生产衣服"""
        for i in range(2000000):
            yield "生产了第%s件衣服"%i
    
    product_g = produce()
    print(product_g.__next__()) #要一件衣服
    print(product_g.__next__()) #再要一件衣服
    print(product_g.__next__()) #再要一件衣服
    num = 0
    for i in product_g:         #要一批衣服,比如5件
        print(i)
        num +=1
        if num == 5:
            break
    
    #到这里我们找工厂拿了8件衣服,我一共让我的生产函数(也就是produce生成器函数)生产2000000件衣服。
    #剩下的还有很多衣服,我们可以一直拿,也可以放着等想拿的时候再拿
    View Code

    生成器监听文件输入的栗子:

    import time
    
    def tail(filename):
        f = open(filename)
        f.seek(0, 2) #从文件末尾算起
        while True:
            line = f.readline()  # 读取文件中新的文本行
            if not line:
                time.sleep(0.1)
                continue
            yield line
    
    tail_g = tail('tmp')
    for line in tail_g:
        print(line)
    View Code

    计算移动平均值(类似于年化收益):

    def averager():
        total = 0
        day = 0
        average = 0
        while True:
            term = yield average
            total += term
            day += 1
            average = total/day
    
    
    g_avg = averager()
    next(g_avg)
    print(g_avg.send(10))
    print(g_avg.send(12))
    print(g_avg.send(13))
    View Code

     

    yield from可以在实行for循环的效果的同时将代码变少:

    def gen1():
        for c in 'AB':
            yield c
        for i in range(3):
            yield i
    
    print(list(gen1()))#['A','B',1,2,3]
    
    
    #简化版本
    def gen2():
        yield from 'AB'
        yield from range(3)
    
    print(list(gen2()))#['A','B',1,2,3]

     

    列表推导式和生成器表达式:(这里用一个小故事讲解知识点)

    #为了彰显高富帅本质,一口气买了十个茶叶蛋,将他们依次排开并编号,拍照发到朋友圈
    
    egg_list=['茶叶蛋%s' %i for i in range(10)] #列表解析
    
    #可是这十个茶叶蛋一口气吃不完啊,要吃也就是一个一个吃,那么就吃一个拍一个照吧
    
    eat=('茶叶蛋%s' %i for i in range(10))#生成器表达式
    print(eat)
    print(next(eat)) #next本质就是调用__next__
    print(eat.__next__())
    print(next(eat))
    高富帅与茶叶蛋

    总结:

    1.把列表解析的[]换成()得到的就是生成器表达式

    2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存

    3.Python使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。

     

     

    附:与生成器相关的面试题:

    def demo():
        for i in range(4):
            yield i
    
    g=demo()
    
    g1=(i for i in g)
    g2=(i for i in g1)
    
    print(list(g1))#[0,1,2,3]
    print(list(g2))#[]
    面试题1
    def add(n,i):
        return n+i
    
    def test():
        for i in range(4):
            yield i
    
    g=test()
    for n in [1,10]:
        g=(add(n,i) for i in g)
    
    print(list(g))#[20,21,22,23]
    面试题2

     

           

  • 相关阅读:
    Structed Exception Handler 学习总结(五)
    Structed Exception Handler 学习总结(四)
    Structed Exception Handler 学习总结(三)
    Structed Exception Handler 学习总结(二)
    Structed Exception Handler 学习总结(一)
    关于模板的思考
    java中的exception与c++中的exception比较
    java中的exception
    在控制台(Console)环境下编译Windows GUI程序
    关于字符串的内存分配问题
  • 原文地址:https://www.cnblogs.com/zhuminghui/p/8206439.html
Copyright © 2011-2022 走看看