• python之生成器和列表推导式


    一、生成器函数
    1、生成器:就是自己用python代码写的迭代器,生成器的本质就是迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现)。
    2、用以下两种方式构建一个生成器:
    1,生成器函数:跟常规函数定义类似,但是,使用yield语句而不是return语句返回结果。
    yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行。

    2,生成器表达式:类似于列表推导,但是,返回的是生成器的一个对象,
    而不是一次构建一个结果列表。

    3、生成器函数
    3-1、先看一般的函数:

    def func1(x):
        x += 1
        return x
    func1(5) #函数的执行命令,并且接收函数的返回值。
    print(func1(5))  #6

    3-2、再看生成器函数:

    复制代码
    def func1(x):
        x += 1
        print(666)
        yield x
        x +=2
        print(777)
        print(x)
        yield 'xiaobai'
        x +=3
    
    g = func1(5)        # 此时的func1(5)不会执行函数,因为它只是生成器函数对象
    print(g)            # <generator object func1 at 0x0000025E5D618780>
    print(g.__next__()) #666 6
    print(next(g))      #777 8 xiaobai
    复制代码


    3-3、yield与return的区别:
    return:结束函数,给函数的执行者返回值
    yield:不会结束函数,一个next对应一个yield,
    执行yield上面的代码并给 生成器对象.__next__() 返回值


    3-4、生成器函数与迭代器的区别
    区别1:自定制的区别
    迭代器由可迭代对象转化而来,已经‘写死了’

    l1 = [1,2,3,4,5]
    l1.__iter__()

    生成器可用自定制函数来定制

    复制代码
    def func1(x):
        x += 1
        yield x
        x += 3
        yield x
        x += 5
        yield x
    g1 = func1(5)
    print(g1.__next__())
    print(g1.__next__())
    print(g1.__next__())
    复制代码


    区别2:内存级别的区别。
    迭代器是需要可迭代对象进行转化,可迭代对象非常占内存。
    生成器直接创建,不需要转化,从本质就节省内存。

    复制代码
    def func1():
        for i in range(1000000):
            yield i
    g1 = func1()
    for i in range(50):
        print(g1.__next__()) #一个next取一次值,可用for循环取值
    复制代码

    3-5、send与next
    先看例子:

    复制代码
    def func1():
        print(1)
        count = yield 6
        
        print(count)
        print(2)
        count1 = yield 7
        
        print(count1)
        print(3)
        yield 8
    
    g = func1()
    print(g.__next__())       #1 6
    print(g.send('xiaobai'))  #xiaobai 2 7
    print(g.send('xiaigou'))  #xiaogou 3 8
    复制代码

    总结:
    send与next一样,也是对生成器取值(执行一个yield)的方法。
    send可以给上一个yield 传值。
    注意小坑:
    1,第一次取值只能用next
    2,最后一个yield不可能得到send传的值

    3-6、生成器close()方法:

    复制代码
    def fun():
        for i in range(5):
            yield i
    g = fun()
    print(g.__next__())
    print(g.__next__())
    print(g.__next__())
    g.close() # 直接把生成器的值取(删)完了,后面就不能再取值
    print(g.__next__()) # 报错
    
    
    a = (i for i in range(4))
    print(a.__next__())
    print(a.__next__())
    a.close()
    print(a.__next__()) #报错
    复制代码

    3-7、生成器函数的应用例子
    要制作一批量很大的衣服,用普通的函数只能一次全部制作完:

    def cloth1(n):
        for i in range(n+1):
            print('衣服%s号' % i)
    cloth1(100000)  #一次全部制作完了

    而用生成器函数,需要制作多少就先制作多少:

    复制代码
    def cloth2(n):
        for i in range(1,n+1):
            yield '衣服%s号' % i
    g = cloth2(10000)
    
    先制作50件:
    for i in range(50):
        print(g.__next__()) #衣服1号,衣服2号,衣服3号...衣服50号
    
    再制作50件:
    for i in range(50):
        print(g.__next__()) #衣服51号,衣服52号,衣服53号...衣服100号
    复制代码


    二、列表推导式,生成器表达式
    1、普通方法创建一个元素为1到100的列表:

    l1 = []
    for num in range(1,101):
        l1.append(num)
    print(l1)

    2、列表推导式:一行代码几乎搞定你需要的任何的列表。
    2-1、两种方式:
      循环模式
      筛选模式

    2-2、循环模式:[变量(加工后的变量) for 变量 in iterable]

    复制代码
    #1到100的列表
    l = [i for i in range(1,101)]
    print(l) #[1,2,3,4...100]
    
    #python1到python15的列表
    l2 = ['python%s' % i for i in range(1,16)]
    print(l2)  #[python1,python2,python3...python15,]
    
    #1到10的平方
    l3 = [i*i for i in range(1,11)]
    print(l3) #[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
    复制代码

    2-3、筛选模式 [变量(加工后的变量) for 变量 in iterable if 条件]

    复制代码
    #30以内的偶数
    l4 = [i for i in range(1,31) if i % 2 == 0]
    print(l4) #[2, 4, 6, 8,10,...28, 30]
    
    #30以内能被3整除的数
    l5 = [i for i in range(1,31) if i % 3 == 0]
    print(l5) #[3, 6, 9, 12, 15, 18, 21, 24, 27, 30]
    
    #30以内能被3整除的数的平方
    l6 = [i**2 for i in range(1,31) if i % 3 == 0]
    print(l6) #[9, 36, 81, 144, 225, 324, 441, 576, 729, 900]
    
    
    #找出列表中含有两个'e'的元素
    names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
             ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
    l7 = [j for i in names for j in i if j.count('e') == 2]
    print(l7) #['Jefferson', 'Wesley', 'Steven', 'Jennifer']
    复制代码

    2-4、列表推导式优缺点
    优点:一行解决,方便。
    缺点:容易着迷,不易排错,不能超过三次循环。
    列表推导式不能解决所有列表的问题,所以不要太刻意用。

    3、生成器表达式:将列表推导式的[]换成()即可。

    复制代码
    g = (i for i in range(100000000000))
    print(g) #生成器表达式左边的变量g是生成器对象
    print(g.__next__())  # 0
    print(g.__next__())  # 1
    print(g.__next__())  # 2
    
    上面代码相当于:
    def func():
        for i in range(100000000000):
            yield i
    g = func()  #生成器对象
    print(g.__next__())
    print(g.__next__())
    print(g.__next__())
    复制代码

    4、扩展
    4-1、字典推导式

    复制代码
    # 例一:将一个字典的key和value对调
    dic = {'a': 10, 'b': 34}
    new_dic = {dic[k]: k for k in dic}
    print(new_dic)
    # 结果:
    # {10: 'a', 34: 'b'}
    
    
    # 例二:合并大小写对应的value值,将k统一成小写
    dic = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}
    new_dic = {k.lower():dic.get(k.lower(),0) + dic.get(k.upper(),0) for k in dic}
    print(new_dic)
    # 结果:
    # {'a': 17, 'b': 34, 'z': 3}
    复制代码

    4-2、集合推导式

    # 例一:计算列表中每个值的平方,自带去重功能
    set1 = {x**2 for x in [1, -1, 2]}
    print(set1)
    # 结果:
    # {1, 4}

    4-3、集合推导式和字典推导式的区别

    复制代码
    相同点:外层都是使用大括号{}
    不同点:返回的形式是 key:values 形式的就是字典,返回的形式是 values1,values2...形式的是集合
    # 集合推导式
    set1 = {x**2 for x in (1, -1, 2)}
    print(set1,type(set1))  # {1, 4} <class 'set'>
     
    
    # 字典推导式
    dic1 = {x**2:x for x in (1, -1, 2)}
    print(dic1,type(dic1))  # {1: -1, 4: 2} <class 'dict'>
    复制代码

    4-4、练习题

    复制代码
    # 例1:  过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母
    l1 = [i.upper() for i in ['asdf','a','b','qwe'] if len(i) >= 3]
    print(l1)
    # 结果:
    # ['ASDF', 'QWE']
    
    # 例2:  求(x,y)其中x是0-5之间的偶数,y是0-5之间的奇数组成的元组列表
    l2 = [(x,y) for x in range(6) if x % 2 ==0 for y in range(6) if y % 2 == 1]
    print(l2)
    # 结果:
    # [(0, 1), (0, 3), (0, 5), (2, 1), (2, 3), (2, 5), (4, 1), (4, 3), (4, 5)]
    
    
    # 例3:  求M中3,6,9组成的列表
    M = [[1,2,3],[4,5,6,24,3],[7,8,9,12,9]]
    l3 = [j for i in M for j in i for z in [3,6,9] if j / z == 1 ]
    print(l3)
    # 结果:
    # [3, 6, 3, 9, 9]
    复制代码

     

     

  • 相关阅读:
    助教观察记录5(10/21-11/3)
    助教观察记录4(10/07-10/20)
    助教观察记录3(9/23-10/06)
    助教观察记录1(9/5-9/15)
    2019年春季学期《C语言程序设计II》课程总结
    2020软件工程个人作业06——软件工程实践总结作业
    软件工程第二次作业
    2020软件工程作业3
    2020软件工程作业01
    神必高考数学题乱写
  • 原文地址:https://www.cnblogs.com/yidashi110/p/10092276.html
Copyright © 2020-2023  润新知