zoukankan      html  css  js  c++  java
  • Python生成器、推导式之前襟后裾

    生成器

    函数体内有yield选项的就是生成器,生成器的本质是迭代器,由于函数结构和生成器结构类似,可以通过调用来判断是函数还是生成器,如下:

    def fun():
        yield "我是生成器"
    print(fun())
    
    # 打印内容如下:
    <generator object fun at 0x0000000002160ED0> 

    生成器的优点就是节省内存.

    Python获取生成器的二种方式:

    • 通过函数获取生成器
    • 通过生成器推导式创建生成器

    通过函数获取生成器

    def fun(): 
        print("fun") 
        yield "生成器" 
    g = fun() 
    print(g)    # 打印函数名查看是否是生成器 
    
    # 打印内容如下:
    <generator object fun at 0x0000000000510ED0> 

    从打印内容可以看出是生成器,但是发现生成器里面的内容没有被打印,那如何打印生成器内容呢?我们可以把生成器理解成迭代器的变异版,所以要打印生成器的内容,与迭代器类似,创建生成器对象后,可以使用生成器.__next__()来打印生成器内容,或者next()、send()等来打印生成器,如下:
    使用.__next__()来打印生成器中的内容:

    def fun():
        print("我在yield 1的上面")
        yield "yield 1"
        print("我在yield 1的下面")
    g = fun() # 创建生成器对象
    print(g.__next__()) # 打印生成器里面的内容
    
    # 打印内容如下
    我在yield 1的上面
    yield 1

    从上面的打印结果可以发现yield下面的print语句没有被打印,到yield停止了。

    def fun():
        print("我在yield 1 上面")
        yield "我是yield 1"
        print("我在yield 1 下面")
        yield "我是yield 2"
        print("我在yield 2 下面") 
    g
    = fun() # 创建生成器对象 print(g.__next__()) print(g.__next__()) # 打印内容如下 我在yield 1 上面 我是yield 1 我在yield 1 下面 我是yield 2

    由上面两个事例我们可以看出就是每next一次就执行一次yield上面的代码一次,yield下面的代码不会被执行,这就是生成器的惰性机制。

    下面使用next()打印生成器内容:

    def fun():
        print("我在yield 1 上面")
        yield "我是yield 1"
        print("我在yield 1 下面")
        yield "我是yield 2"
        print("我在yield 2 下面")
    
    g = fun()
    print(next(g)) # next(g)打印生成器内容
    print(next(g)) # next(g)打印生成器内容
    
    # 打印内容如下
    我在yield 1 上面
    我是yield 1
    我在yield 1 下面
    我是yield 2

    与.__next__()功能类似

    在使用send(参数)打印生成器内容:
    send方法可以给上一层的yield传递一个值,如果上一个yield没有值的话send的参数将被忽略,如果有值yield的值将被改变成当前的参数,还有需要注意的地方就是如果send(参数)做为第一次迭代,由于上一层没有yield,所以没有办法传参,会导致出现错误,错误内容如下:
    TypeError: can't send non-None value to a just-started generator
    我们将send(None)作为第一次调用即可,然后在第二次调用时可以传适当的参数如下:

    def fun():
        val = yield "我是yield 1"
        print(val)
        val = yield "我是yield 2"
        print(val)
        yield "我是yield 3"
        print("我在yield 3 下面")
    
    g = fun()
    print(g.send(None))
    print(g.send("我是send 2"))
    print(g.send("我是send 3"))
    
    # 打印内容如下
    我是yield 1
    我是send 2
    我是yield 2
    我是send 3
    我是yield 3

    使用for循环打印生成器所有内容。

    def fun():
        yield "我是yield 1"
        yield "我是yield 2"
        yield "我是yield 3"
    
    g = fun() # 创建生成器对象
    for g_buf in g: # 使用for循环打印生成器对象
        print(g_buf)
    
    # 打印内容如下
    我是yield 1
    我是yield 2
    我是yield 3

    yield可以返回任何数据类型,这里以列表为事例:

    def fun(): 
        list_1 = [1,2,3,4,5] 
        yield list_1 # 将整个列表作为返回值传给生成器对象
    g = fun() # 创建生成器对象 
    print(g.__next__()) # 打印生成器对象 
    
    # 打印内容如下:
    [1, 2, 3, 4, 5] 

    如果想要yield从列表中每次返回一个元素可以使用yield from 列表来实现,如下:

    def fun(): 
        list_1 = [1,2,3,4,5] 
        yield from list_1 
    g = fun() # 创建生成器对象 
    print(g.__next__()) # 打印生成器对象内容 
    
    # 打印内容如下:
    1 

    可以发现只打印了列表中的一个元素,可以使用for循环打印所有内容:

    def fun(): 
        list_1 = [1,2,3,4,5] 
        yield from list_1 
    g = fun() 
    for g_buf in g: 
    print(g_buf) 
    
    # 打印内容如下:
    1 
    2 
    3 
    4 
    5 

    相当于执行了5次print(g.__next__())  打印生成器所有内容。

    推导式

    列表推导式

    如给list_1列表赋值,常规做法如下:

    list_1 = [] 
    for num in range(10): 
        list_1.append(num) 
    print(list_1) 
    
    # 打印内容如下
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

    使用列表推导式如下:

    list_1 = [num for num in range(10)] 
    list_2 = ["Python: %s" % num for num in range(3)]
    print(list_1) 
    print(list_2) 
    
    # 打印内容如下
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    ['Python: 0', 'Python: 1', 'Python: 2']

    列表推导式还可以进行筛选,如下:

    list_1 = [num for num in range(20) if num < 5 or num == 15]
    print(list_1) 
    
    # 打印内容如下:
    [0, 1, 2, 3, 4, 15] 

    升级一点,将一个嵌套列表中以"a"开头和以"h"开头的元素存放在一个空列表中,基础写法如下:

    names = [['abc', 'abb', 'zzz'],["hello","world","xiaoming"]] 
    list_names = [] 
    for name_1 in names: 
        if type(name_1) == list: 
            for name_2 in name_1: 
                if name_2.startswith("a") or name_2.startswith("h"):
                    list_names.append(name_2) 
    print(list_names) 
    
    # 打印内容如下:
    ['abc', 'abb', 'hello']         

    使用列表推导法:

    names = [['abc', 'abb', 'zzz'],["hello","world","xiaoming"]] 
    list_names = [name_2 for name_1 in names if type(name_1) for name_2 in name_1 if name_2.startswith("a") or 
    name_2.startswith("h")] 
    
    # 打印内容如下:
    ['abc', 'abb', 'hello'] 

    生成器推导式

    与列表推导式类似,只不过列表是使用[],生成器推导式使用的是()。

    g_1 = (num for num in range(10)) 
    print(g_1) 
    print(g_1.__next__()) 
    print(g_1.__next__()) 
    # 打印内容如下 <generator object <genexpr> at 0x0000000002FAACA8> 0 1

    我们知道生成器是具有惰性的,每次只能获取一条数据,下面使用for循环打印所有内容:

    g_1 = (num for num in range(10)) 
    for num in g_1:
        print(num,end=' ') 
    
    # 打印内容如下
    0 1 2 3 4 5 6 7 8 9 

    生成器的筛选与列表推导式用法一样,只不过是()。
    如下:过滤1-20内的所有偶数。

    g_1 = (num for num in range(20) if num % 2 == 0)
    for i in g_1:
        print(i,end=" ")
    
    # 打印内容如下
    0 2 4 6 8 10 12 14 16 18 

    生成器表达式和列表推导式的区别:

    • 列表推导式比较耗内存,一次性加载全部数据,生成器表达式几乎不占用内存,使用的时候才分配和使用内存。
    • 得到的值不一样,列表推导式得到的是一个列表全部数据,生成器表达式获取的是一个生成器。

    字典推导式

    list_1 = ["电视剧","电影"] 
    list_2 = ["上海滩","黄飞鸿"] 
    dict_1 = {list_1[i]:list_2[i] for i in range(len(list_1))} 
    print(dict_1) 
    
    # 打印内容如下:
    {'电视剧': '上海滩', '电影': '黄飞鸿'} 

    集合推导式

    集合的特点:无序、不重复所以集合推导式自带去重功能。

    list_1 = [1,2,3,4,2,3,5] 
    set_1 = {i for i in list_1} # 集合推导式 
    print(set_1) 
    
    # 打印内容如下:
    {1, 2, 3, 4, 5}

    总结:

    • 推导式有列表推导式、生成器推导式、字典推导式、集合推导式。
    • 生成器表达式:(结果 for 变量 in 可迭代对象 if 条件筛选)
    • 生成器表达式可以直接获取到生成器对象,生成器对象具有惰性,每次只能获取一条内容,可以使用for循环打印生成器所有的内容。

    下一篇:装饰器,常用内置函数:https://www.cnblogs.com/caesar-id/p/10328512.html

  • 相关阅读:
    将已排序的数组乱序
    Roadmap!!
    测试
    最大对称字串
    约瑟夫环问题
    大家好
    MYSQL数据库导入SQL文件出现乱码如何解决
    Hibernate缓存
    Spring备忘四(涵盖Spring2.5)
    Struts2 Hello,Wold
  • 原文地址:https://www.cnblogs.com/caesar-id/p/10316858.html
Copyright © 2011-2022 走看看