《Python》 生成器和列表推导式

一、初识生成器:

    生成器就是自己用Python代码写的迭代器,生成器的本质就是迭代器。

    1、Python中提供的生成器:

      1、生成器函数:

        使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行。

      2、生成器表达式:

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

    2、生成器Generator:

      本质:迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现)

      热点:惰性运算,开发者自定义

二、生成器函数:

    一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值,但是yield又不同于return。

    yield和return的区别:

      return:结束函数,给函数的执行者返回值。

      yield:不会结束函数,一个next对应一个yield,给 生成器对象.__next__() 返回值

    生成器函数vs迭代器:

      1.自定制取值:

 1 只能一个一个取值:
 2 l1 = [1,2,3,4,5]
 3 l1.__iter__()
 4 
 5 可以自定义取值:
 6 def func1(x):
 7     x += 1
 8     yield x
 9     x += 3
10     yield x
11     x += 5
12     yield x
13 g1 = func1(5)
14 print(g1.__next__())
15 print(g1.__next__())
16 print(g1.__next__())
自定制的区别

      2、内存级别的区别:

        迭代器是需要可迭代对象进行转换,可迭代对象非常占内存。

        生成器直接创建,不需要转化,从本质就节省内存。

def func1():
    for i in range(1000000):
        yield i
g1 = func1()
for i in range(50):
    print(g1.__next__())
生成器按需取值
 1 import time
 2 def genrator_fun1():
 3     a = 1
 4     print('现在定义了a变量')
 5     yield a
 6     b = 2
 7     print('现在又定义了b变量')
 8     yield b
 9 
10 g1 = genrator_fun1()
11 print('g1 : ',g1)       #打印g1可以发现g1就是一个生成器
12 print('-'*20)   #我是华丽的分割线
13 print(next(g1))
14 time.sleep(1)   #sleep一秒看清执行过程
15 print(next(g1))
16 
17 初识生成器函数
初始生成器函数

生成器有什么好处呢?就是不会一下子在内存中生成太多数据

假如我想让工厂给学生做校服,生产2000000件衣服,我和工厂一说,工厂应该是先答应下来,然后再去生产,我可以一件一件的要,也可以根据学生一批一批的找工厂拿。
而不能是一说要生产2000000件衣服,工厂就先去做生产2000000件衣服,等回来做好了,学生都毕业了。。。

def produce():
    """生产衣服"""
    for i in range(2000000):
        yield "生产了第%s件衣服"%i

product_g = produce()
print(product_g.__next__()) #要一件衣服
print(product_g.__next__()) #再要一件衣服
print(product_g.__next__()) #再要一件衣服
num = 0
for i in product_g:         #要一批衣服,比如5件
    print(i)
    num +=1
    if num == 5:
        break
生成器按需取值

三、send

   send和next一样,也是对生成器取值(执行一个yield)的方法。

   send可以给上一个yield传值。

   第一次取值永远都是next。

   最后一个yield永远也得不到send传的值。

def generator():
    print(123)
    content = yield 1
    print('=======',content)
    print(456)
    yield2

g = generator()
ret = g.__next__()
print('***',ret)
ret = g.send('hello')   #send的效果和next一样
print('***',ret)
send的用法

四、列表推导式和生成器表达式   

    1.把列表解析的[]换成()得到的就是生成器表达式

    2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存

    3.Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。

    一、列表推导式:一行代码几乎搞定你需要的任何的列表

        优点:一行解决,方便。

        缺点:容易着迷,不易排错,不能超过三次循环。

           列表推导式不能解决所有列表的问题,所以不要太刻意用。

      1、循环模式:[ 变量(加工后的变量) for  变量  in  可迭代对象 ]

        prite([ i for i in range(1,101)]) # 循环打印1~100

        prite([ ‘Python第%s期’ % i for i in range(1,16)]) 

      2、筛选模式:[ 变量(加工后的变量)for  变量  in  可迭代对象  if  条件 ]

        prite([ i  for  i  in  range(1,31)  if  i  %  3  ==  0 ])  #打印30以内能被3整除的数

        prite([ i ** 2  for  i  in  range(1,31)  if  i  %  3  ==  0 ])  #打印30以内能被3整除的数的平方

names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
         ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]

print([name for lst in names for name in lst if name.count('e') >= 2])  # 注意遍历顺序,这是实现的关键
找到嵌套列表中名字含有两个‘e’的所有名字     

    二、字典推导式:      

mcase = {'a': 10, 'b': 34}
mcase_frequency = {mcase[k]: k for k in mcase}
print(mcase_frequency)
将一个字典的key和value对调
mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}
mcase_frequency = {k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase.keys()}
print(mcase_frequency)
合并大小写对应的value值,将k统一成小写

    三、集合推导式:

squared = {x**2 for x in [1, -1, 2]}
print(squared)
# Output: set([1, 4])
计算列表中每个值的平方,自带去重功能
原文地址:https://www.cnblogs.com/yzh2857/p/9506080.html