• 生成器、迭代器


    一、列表生成式

    现在有个需求,看列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],要求你把列表里的每个值加1

    a = [i+1 for i in range(10)]
    print(a)
    
    输出:
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    这样的写法就叫做列表生成式

    二、生成器(generator

    要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

    g = (i+1 for i in range(10))  # 创建了一个generator

    相当于generator保存了一种算法,当你需要时才给你生成数据,你不需要,它就停在那里,这与列表相比,比较节省内存空间。
    generator只能前进,不能往后退,当生成完了之后就不再生产。

    可以通过next()函数获得生成器的下一个值,若生产完了就会报错。

    可以用for循环或while循环来迭代generator:

    g = (i+1 for i in range(3))  # 创建了一个generator
    for n in g:
        print(n)
    
    输出:
    1
    2
    3
    View Code

    使用for循环,当生成完之后不会报错。


    在python3中,range()就是一个生成器,执行语句:print(range(3)) ,结果是:range(0,3)

    在python2中,执行语句:print(range(3)) ,结果是:0,1,2 ,相当于range()是一个列表

    在python2中,执行语句:print(xrange(3)) ,结果是:range(0,3),与python3一样,是一个生成器

    斐波拉契数列

    斐波那契数列指的是这样一个数列 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89,..........

    第0项是0,第1项是第一个1。这个数列从第2项开始,每一项都等于前两项之和。

      有如下代码:

    def fib(max):
        n, a, b = 0, 0, 1  # n:循环次数,a:第一个数,b:第二个数
        while n <= max:
            print(b)
            a, b = b, a+b
            n += 1
        return
    
    fib(4)
    
    输出:
    1
    1
    2
    3
    5
    View Code

    程序将会输出所有计算结果。
      使用生成器:

    def fib(max):
        n, a, b = 0, 0, 1  # n:循环次数,a:第一个数,b:第二个数
        while n <= max:
            yield b  # 把函数的执行结果冻结在这一步,并且把b的值返回给外面的next(f)
            a, b = b, a+b
            n += 1
    
    
    f = fib(4)
    print(next(f))  # 调用才会生成
    print(next(f))
    
    输出:
    1
    1
    View Code

    这便是定义generator的另一种方法:如果函数定义中包含了yield关键字,那么这个函数就不再是一个普通的函数,而是一个生成器。
      函数与生成器的区别:

    它们的执行流程不同,函数是顺序执行,遇到return或者函数最后一行语句时结束;生成器是在每次调用next()的时候执行,遇到yield语句返回,再次next()调用时,从上次返回的yield语句处继续执行。

    return的作用:返回并终止函数

    yield的作用:返回并冻结当前的执行过程,(即停留在这一步)

    next()的作用:唤醒冻结的执行过程,继续执行,直到遇到下一个yield

    send()的作用:唤醒冻结的执行过程,继续执行,并发送一个消息到生成器内部

    注意:在生成器中使用return,程序会报错。

    def func(n):
        count = 0
        while count < n:
            print(count)
            count += 1
            sign = yield count
            if sign == "stop":  # 当收到“stop”时停止生产
                print("sign:", sign)
                break
            else:
                print("continue:", sign)
    
    
    res = func(5)
    print(next(res))
    res.send("start")
    res.send("stop")
    
    输出:
    0
    1
    continue: start
    1
    sign: stop
    View Code

    三、迭代器

      可以直接作用于for循环的对象统称为可迭代对象:Iterable

    包括以下几种数据类型:

    一类是集合数据类型,如listtupledictsetstr等;

    一类是generator,包括生成器和带yield的generator function。

    可以使用isinstance()判断一个对象是否是Iterable对象:

    from collections import Iterable
    print(isinstance([], Iterable))  # 判断列表是否是可迭代对象
    print(isinstance({}, Iterable))  # 判断字典是否是可迭代对象
    print(isinstance("asdfg", Iterable))  # 判断字符串是否是可迭代对象
    print(isinstance((x for x in range(10)), Iterable))  # 判断生成器是否是可迭代对象
    print(isinstance(100, Iterable))  # 判断数字是否是可迭代对象
    
    输出:
    True
    True
    True
    True
    False
    View Code

      可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。

    可以使用isinstance()判断一个对象是否是Iterator对象:

    from collections import Iterator
    print(isinstance([], Iterator))  # 判断列表是否是迭代器
    print(isinstance({}, Iterator))  # 判断字典是否是迭代器
    print(isinstance("asdfg", Iterator))  # 判断字符串是否是迭代器
    print(isinstance((x for x in range(10)), Iterator))  # 判断生成器是否是迭代器代对象
    print(isinstance(100, Iterator))  # 判断数字是否是迭代器
    
    输出:
    False
    False
    False
    True
    False
    View Code

    生成器都是Iterator对象,但listdictstr虽然是Iterable,却不是Iterator

    listdictstrIterable变成Iterator可以使用iter()函数:

    from collections import Iterator
    print(isinstance(iter([]), Iterator))  # 将列表变为迭代器
    
    输出:
    True
    View Code

      你可能会问,为什么listdictstr等数据类型不是Iterator

    这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

    Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

    小结

    凡是可作用于for循环的对象都是Iterable类型;

    凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

    集合数据类型如listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

    Python3的for循环本质上就是通过不断调用next()函数实现的,例如:

    for x in [1, 2, 3, 4, 5]:
        print(x)
    View Code

     

    实际上完全等价于:

    it = iter([1, 2, 3, 4, 5])  # 获得一个Iterator对象
    
    while True:  # 循环
        try:
            x = next(it)  # 获得下一个值
            print(x)
        except StopIteration:
            break  # 遇到StopIteration就退出循环
    View Code

     

     

     

  • 相关阅读:
    Convert Sorted Array to Binary Search Tree数组变成高度平衡的二叉树
    695. Max Area of Island最大岛屿面积
    257. Binary Tree Paths返回所有深度优先的遍历
    112. Path Sum二叉树路径和
    对称二叉树 · symmetric binary tree
    100. Same Tree同样的树
    计数排序 (Counting Sort)
    基数排序 (Radix Sort)
    Linux 文件基本属性
    gensuitemodule (Mac OS) – Python 中文开发手册
  • 原文地址:https://www.cnblogs.com/yanlin-10/p/9017353.html
Copyright © 2020-2023  润新知