• 03python 迭代器与生成器(python函数)


     

    迭代器

    什么叫做迭代器?

      在回答这个问题之前应该先要了解到什么叫做迭代

    >>> dir([1, 2])
    ['__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']
    >>> dir((1, 3, 4))
    ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index']

     我们查看可迭代的数据类型列表以及元组的属性时,都能找到一个共同的双下方法"__iter__"

    可迭代协议就是:只要含有__iter__()方法的都是可迭代的。

    那什么又叫做迭代器那?迭代器跟可迭代又有什么关系?

    再看一段代码

    >>> print([1, 2].__iter__())
    <list_iterator object at 0x0000002DE6FDFDD8>    # iterator 迭代器的意思

     到这里其实就已经找到了答案。什么叫做迭代器啦?就是可迭代数据类型调用[ ].__iter__()方法,返回的就是一个迭代器

    迭代器有什么用?
    >>> dir([1, 2].__iter__())
    ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__length_hint__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__']

     仔细观察上面的双下方法会发现三个从前没有接触过的

    __length_hint__()     # 获取迭代器中元素的长度
    __setstate__()       # 根据索引值指定从哪里开始迭代
    __next__()            # 一个一个的取值
    >>> l = [1, 2, 3, 4, 5, 6, 7]
    >>> l_it = l.__iter__()
    >>> l_it.__length_hint__()
    7
    >>> l_it.__setstate__(2)
    >>> l_it.__next__()
    3
    >>> l_it.__next__()
    4
    >>> 

    其实啊迭代器的作用关键就在__next__()方法。在取数据的时候一条一条的取。有时候在读取一些不知道多大内存的文件时,显然__next__()会比写for循环取更安全。


    生成器

    生成器的本质:就是一个迭代器,它是由我们自定义的,且是惰性运算的

    python中的生成器

    1. 生成器表达式
    2. 生成器函数

    生成器表达式

    >>> it = (i for i in range(5))
    >>> it
    <generator object <genexpr> at 0x0000002DE6FDB830>
    >>> it.next()        # 貌似py3不支持这种写法
    Traceback (most recent call last):
      File "<pyshell#17>", line 1, in <module>
        it.next()
    AttributeError: 'generator' object has no attribute 'next'
    >>> it.__next__()
    0
    >>> it.__next__()
    1

    生成器表达式是不是可以叫做元组解析、元组表达式?

    生成器函数

    >>> def produce():
        """生产娃娃"""
        for i in range(2000000):
            yield "生产了%d个娃娃" % i
    
            
    >>> product_g = produce()       # 调用生成器函数
    >>> product_g
    <generator object produce at 0x000000E884B51C50>
    >>> product_g.__next__()
    '生产了0个娃娃'
    >>> product_g.__next__()
    '生产了1个娃娃'

    生成器函数的定义也特别简单就是返回值由return变成了yield

    生成器的方法send

    def generator():
        print(123)
        yield 1
        print(456)
        arg = yield 2
        yield arg
    
    g = generator()
    ret = g.__next__()
    print(ret)
    ret = g.send('hello')        # 没有变量来接收
    print(ret)
    ret = g.send('hello')        # send的参数被arg接收到了
    print(ret)                    # 返回arg
    
    >>>123
    1
    456
    2
    hello
    # 利用生成器求平均值
    def average():
        sum = 0
        count = 0
        avg = 0
        while True:
            num = yield avg
            sum += num
            count += 1
            avg = sum / count
    
    
    avg_g = average()
    avg_g.__next__()
    avg1 = avg_g.send(10)
    print(avg1)
    avg2 = avg_g.send(20)
    print(avg2)

     注意send的用法:
      send的作用和__next__()一样,send能够传递参数给生成器函数,前提是要有变量来接收

      生成器第一次取值不能使用 send

      生成器函数的最后一个yield不能接收新的值

  • 相关阅读:
    hdu 1171 Big Event in HDU (01背包)
    Codeforces 86C Genetic engineering (AC自己主动机+dp)
    ANDROID L——Material Design具体解释(动画篇)
    三层架构理论篇
    Linux下的tree命令 --Linux下文件夹树查看
    排序之冒泡排序、插入排序及希尔排序
    TRIZ系列-创新原理-9~11-预先反作用原理、预处理原理、预先防范原理
    Linux 获得机器的IP和网卡信息
    Hackerrank
    Android编程之Fragment使用动画造成Unknown animation name: objectAnimator异常
  • 原文地址:https://www.cnblogs.com/pontoon/p/10240024.html
Copyright © 2020-2023  润新知