• python语法基础-函数-迭代器和生成器-长期维护


     ###############    迭代器    ##############

    """
    迭代器
    
    这是一个新的知识点
    我们学习过的可以迭代的对象有哪些?
    list
    str
    dict
    元组
    文件
    集合
    range()
    enumerate
    
    为什么可以被循环?
    
    """
    print(dir([]))  # dir可以查看这个数据类型所有的方法
    """
    ['__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']
    """
    # 双下滑线的方法,我们叫做双下方法,
    # 都是c语言写的,可以不只一个方式去使用
    print([1].__add__([2]))
    print([1]+[2])
    # 这两句是一样的,
    # 正常情况下不使用双下滑线的方法,就可以完成基本的功能了,
    
    # 这些数据类型可以被迭代是因为他们里面内置了一个双下方法,叫做  '__iter__',只要是能被for循环的数据类型都有这个方法,
    print([].__iter__())  # 列表调用了这个方法,就是返回了一个迭代器,<list_iterator object at 0x0000000001DEC048>
    list1 = [1,2,3,4]
    iterator = list1.__iter__()
    print(iterator.__next__())  # 这是读取下一个,一个一个的取值,
    
    # '__iter__',这是可迭代协议
    # 迭代器协议,内部含有'__iter__',__next__(),这两个方法就是迭代器,
    
    from collections import Iterable
    from collections import Iterator
    
    print(isinstance([],Iterable))  # true
    print(isinstance([],Iterator))  # false  列表不是迭代器,
    # isinstance判断一个数据类型是不是第二个参数,
    
    class A:
        def __iter__(self):pass
        def __next__(self):pass
    
    a = A()
    print(isinstance(a,Iterable))
    print(isinstance(a,Iterator))
    # 由此可以证明,只有有__iter__',__next__(),这两个方法就是迭代器,
    
    #########################################################
    """
    总结:
    迭代器协议,要同时具有__iter__',__next__(),这两个方法就是迭代器,,可迭代的不一定是迭代器,因为要有next方法, 
    可迭代协议,只要能被for循环就是可迭代的,如果是迭代器一定是可迭代的,因为里面有iter方法, 
    next方法可以一个一个取值,for循环就是使用迭代器,
    
    #####
    在工作中可能会遇到迭代器,你要认识,
    第一种是明确告诉了你是一个   iterater,print([].__iter__())  ,<list_iterator object at 0x0000000001DEC048>
    第二种就是range(10)这种就是一个迭代器,
    只有是迭代器才可以被for循环,可以使用isinstance判断是否是一个迭代器,
    
    迭代器的好处:
    1,可以循环取值,
    2,节省内存空间,比如
    range(100000000), 这个还没有生成,没有在内存中生成,是一个一个给你的,
    list(range(100000000)),这个需要一次性生成,会消耗内存,
    比如文件句柄,也是一个可迭代对象,可以一点一点的读取,一次性读取会内存爆掉,
    
    迭代器很好,既能循环还能节省内存,
    在工作中我们会遇到一些情况,不想直接在内存产生,想要一点点的产生,就要用到自己写迭代器
    自己写的迭代器就是生成器,
    
    """
     

    ###############    生成器---生成器函数    ##############

    """
    生成器
    
    之前讲的iter方法和next方法,工作中基本不会用到,因为for循环已经做了这件事,
    这是为了讲解迭代器的原理,还有就是为了生成器做铺垫,
    
    生成器的本质还是迭代器,就是自己写的迭代器,
    有两种方法写生成器
    1,生成器函数
    2,生成器表达式,
    
    """

    第一种:生成器函数,

    #生成器函数
    
    # 1,只要有yield关键字的函数就是生成器函数,
    # 2,yield只能写到函数里面,外边不能写,
    # 3,yield不能和return共用
    # def generator():
    #     print(1)
    #     yield "a"
    #
    # ret = generator()
    # print(ret)
    # <generator object generator at 0x0000000002256B48>
    # 1,只要是生成器函数,调用函数会接收到一个生成器,函数内部的代码是不会执行的,
    # 2,这个生成器也有__iter__(),__next__())两个方法,所以生成器也是一个迭代器,
    # print(ret.__iter__())
    # print(ret.__next__())
    # 3,既然是迭代器我就可以使用next方法,这个next就是去执行函数内部的代码了,
    
    
    def generator():  # 这是一个生成器函数,
        print(1)
        yield "a"
        print(2)
        yield "b"
    
    g = generator()  # 这是一个生成器
    # print(g.__next__())  # 这一步会打印1,a
    # print(g.__next__())  # 这一步会打印2,b,
    # 1,yield不会把代码结束,return会把代码结束,
    # 也可以进行for循环
    for i in g:
        print(i)
    
    ##############################################################
    # 需求:生成200个娃哈哈,
    
    def wahaha():
        for i in range(2000000):
            yield "娃哈哈%d"%i
    
    g = wahaha()
    # for i in g:
    #     print(i)
    # 如果我想要50个怎么办?使用计数器
    count = 0
    for i in g:
        count += 1
        print(i)
        if count >50:
            break
    # 还可以继续取值
    print(g.__next__())
    # 如果是列表,就不能继续取值,因为列表不是迭代器,是可迭代对象
    
    
    #################################################################################
    # 监听文件的输入,就是在文件输入一句,就打印一句
    
    
    # def tail(filename):
    #     f = open(filename, encoding="utf-8")
    #     while True:
    #         line = f.readline()
    #         if line.strip():
    #             yield line.strip()
    #
    # t = tail("file")
    #
    # for i in t:
    #     # 拿到了这个i,就可以对它进行处理了,可以判断,可以前后加内容,
    #     print("***",i)
    #     print(i)

     生成器函数进阶:

    # 生成器函数进阶
    def generator():  # 这是一个生成器函数,
        print(1)
        content = yield "a"
        print("######",content)
        print(2)
        yield "b"
    
    g = generator()
    print(g.__next__())
    print(g.send("hello"))  # send和获取下一个值的效果和next一样,但是可以再执行下一个yield的时候传递一个值,
    """
    1
    a
    ###### hello
    2
    b
    
    使用send的注意事项:
    1,第一次使用生成器的时候,使用next获取下一个值,
    2,最后一个yield,不能接收外部的值,如果你非要接收,那就要最后写一个yield,不需要有返回值,
    
    使用next取值和for循环取值比较常用,send用的比较少,但是要知道,

    """

    ###############    生成器---生成器表达式    ##############

    # 生成器表达式
    
    # 列表推导式,
    list1 = ["鸡蛋%d"%i for i in range(10)]
    print(list1)
    
    # 生成器表达式
    g = (i for i in range(10))
    # g是一个生成器,
    # 和列表推导式的不同点
    # 1,括号不一样,
    # 2,返回值不一样,
    # 生成器表达式几乎不占用内容,这是它的优点,缺点就是返回值还是一个表达式,取值需要第二步,
    
    # 生成器表达式只能做简单的事情,想要复杂的功能的生成器还是生成器函数,
    # 这些推导式你不会没有任何影响,使用for循环和生成器函数都能解决,只是面试的时候会有,别人的代码会有,所以你要掌握
    
    

    #############################################

    #############################################

  • 相关阅读:
    自定义CSS样式,在Hover的基础上面改成
    如何获取上次访问的url地址
    霍英东:大佬的黄昏 刚看的一篇文章很有感触,摘录一点东西
    把用户当傻子的终将被用户鄙视,—|—
    WinForm支持拖拽效果
    【EntityFramework系列教程五,翻译】在ASP.NET MVC程序中借助EntityFramework读取相关数据
    关于“验证码的制作”的一些补充
    【EntityFramework系列教程六,翻译】在ASP.NET MVC程序中使用EntityFramework对相关数据进行更新
    【EntityFramework系列教程四,翻译】为ASP.NET MVC程序创建更为复杂的数据模型
    【EntityFramework系列教程三,翻译】在ASP.NET MVC程序中使用EntityFramework对数据进行排序、过滤筛选以及实现分页
  • 原文地址:https://www.cnblogs.com/andy0816/p/12289725.html
Copyright © 2020-2023  润新知