美文网首页python小小白
Python进阶|列表生成式、列表生成器

Python进阶|列表生成式、列表生成器

作者: 凡有言说 | 来源:发表于2020-01-02 16:58 被阅读0次

    列表生成式

    列表生成式是Python内置的非常简单却强大的可以用来创建list的生成式。

    list1 = [i for i in range(10)]
    list1
    
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    

    比如像获取平方数,若使用常规写法:

    list2 = []
    for x in range(10):
        list2.append(x*x)
    
    list2
    
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    

    若使用列表生成式

    list2 = [x*x for x in range(10)]
    
    list2
    
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    

    当然我们也可以在列表生成式里加入判断条件,比如获取偶数的平方:

    list3 = [x*x for x in range(10) if x%2 == 0]
    
    list3
    
    [0, 4, 16, 36, 64]
    

    此外,也可以做嵌套循环,比如

    list4 = [x+y for x in "ABC" for y in "XYZ"]
    
    list4
    
    ['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
    

    列表生成器
    通过上面的列表生成式,我们可以直接创建一个列表。如果此时想创建一个几百万个元素的列表,这种方式就不大可取。一是占用内存多,二是如果仅访问前面若干元素,那该列表占用的内存空间就浪费了。
    此时,若列表元素可以按照某种算法推算出来,那就可以在循环的过程中不断推算出后续的元素。幸运的是,在Python中有这种一边循环一边计算的机制,它称为生成器。

    list51 = [i for i in range(10)]
    list52 = (i for i in range(10))
    
    print(list51)
    print(list52)
    
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    <generator object <genexpr> at 0x000002877DF0F5E8>
    

    我们可以通过 next() 来调用这个生成器里面的元素

    next(list52)
    
    0
    
    next(list52)
    
    1
    

    我们可以对比下生成式和生成器的耗时,比如我们像生成1亿个元素:

    #计算时间
    
    import time
    
    def func_time(func):
        def wrapper():
            start_time = time.perf_counter()
            my_func = func()
            end_time = time.perf_counter()
            print("方法{}消耗了{}ms".format(func.__name__, (end_time-start_time)*1000))
            return my_func
        return wrapper
    
    @func_time
    def calculate_func_1():
        list1 = [i for i in range(100000000)]
    
    @func_time
    def calculate_func_2():
        list2 = (i for i in range(100000000))
        
    calculate_func_1()
    calculate_func_2()
    

    结果是:

    方法calculate_func_1消耗了13234.298399999943ms
    方法calculate_func_2消耗了0.011099999937869143ms
    

    可以看出,生成器生成的列表 list2 所消耗的时间远低于 list1。这是因为用列表生成式的列表是固定的,即list1中封装的元素格式就是1亿个。
    而lis2则是记录了一定的算法规则,比如上例中的+=i,生成器不需要把数据全部装进list2,而是等到我们需要的时候,算一下然后把数据返回给我们,从而节省了空间。

    最后来了解下yield,它和return有点像。对于return,只要执行了到它,就会返回相应的结果并且终止函数的执行:

    def add():
        a = 1 
        b = 2
        return a + b
        print("ABC")
    
    add()
    
    3
    
    def foo():
        print("a")
        yield
        print("b")
        yield
        print("c")
    
    foo()
    
    <generator object foo at 0x000002877DF0F4F8>
    

    没看到返回值,但发现了生成器的身影。原来,一个函数里如果被定义了yield,那么这个函数就是一个生成器。

    def foo():
        print("a")
        yield
        print("b")
        yield
        print("c")
    
    f = foo()
    next(f)
    
    a
    

    第一次调用时,遇到第一个yield就跳出了函数。

    next(f)
    
    b
    

    第二次调用时,就从第一个yield开始,遇到第二个yield跳出函数。

    我们可以对生成器进行遍历

    def foo():
        for i in range(5):
            yield i*2
    
    for i in foo():
        print(i)
    
    0
    2
    4
    6
    8
    

    当我们去遍历它的时候,生成器会通过特定的算法不断的推断出相应的元素,边运行边推算结果,节省空间。

    参考资料:
    列表生成式
    生成器
    yield和生成器

    公众号.png

    相关文章

      网友评论

        本文标题:Python进阶|列表生成式、列表生成器

        本文链接:https://www.haomeiwen.com/subject/nttnoctx.html