生成器 推导式

生成器 推导式

生成器 Generator

本质:(就是迭代器)

  • 迭代器(所以自带了(_ iter ) 方法和 ( next _)方法,不需要我们去实现)

特点:

  • 惰性运算,开发者自定义

生成器的构建方式

生成器函数

ef func():
    print(11)
    yield 22
ret = func()
print(ret)  
# 运行结果:<generator object func at 0x000001A575163888> 生成器
print(next(ret)) # 22 一个next对应一个yield

生成器推导式(表达式)

python内置函数或者模块提供

def func():
     print("111")
     yield 222
     print("333")
     yield 444
gener = func() # 这个时候函数不会执⾏. ⽽是获取到⽣成器
ret = gener.__next__() # 这个时候函数才会执⾏
print(ret)  # 并且yield会将func生产出来的数据 222 给了 ret。  
ret2 = gener.__next__()
print(ret2)  # 最后⼀个yield执⾏完毕. 再次__next__()程序报错,与迭代器一样。
#  打印结果: 111
            222
            333
            444

return 与 yield的区别

return

  • 一般在函数中只设置一个,他的作用是终止函数,并且给函数的执行者返回值。

yield

  • 在生成器函数中可设置多个,他并不会终止函数,next会获取对应yield生成的元素。
  • 一个yield有多个值以 元组 返回

生成器的作用:节省内存

send 方法(了解)

send注意事项

  • 第一次使用生成器的时候 是用next获取下一个值
  • 最后一个yield不能接受外部的值
# next只能获取yield生成的值,但是不能传递值。
def gen(name):
    print(f'{name} ready to eat')
    while 1:
        food = yield
        print(f'{name} start to eat {food}')
dog = gen('alex')
next(dog)
next(dog)
next(dog)

# 而使用send这个方法是可以的。
def gen(name):
    print(f'{name} ready to eat')
    while 1:
        food = yield 222
        print(f'{name} start to eat {food}')
​
dog = gen('alex')
next(dog)  # 第一次必须用next让指针停留在第一个yield后面
# 与next一样,可以获取到yield的值
ret = dog.send('骨头')
print(ret)
​
def gen(name):
    print(f'{name} ready to eat')
    while 1:
        food = yield
        print(f'{name} start to eat {food}')
dog = gen('alex')
next(dog)
# 还可以给上一个yield发送值
dog.send('骨头')
dog.send('狗粮')
dog.send('香肠')

yield from

# 对比yield 与 yield from 
def func():
    lst = ['卫龙','老冰棍','北冰洋','牛羊配']
    yield lst
g = func()
print(g)
print(next(g))  # 只是返回一个列表
​
def func():
    lst = ['卫龙','老冰棍','北冰洋','牛羊配']
    yield from lst
g = func()
print(g)
# 他会将这个可迭代对象(列表)的每个元素当成迭代器的每个结果进行返回。
print(next(g))
print(next(g))
print(next(g))
print(next(g))
'''
yield from ['卫龙','老冰棍','北冰洋','牛羊配'] 
等同于:
    yield '卫龙'
    yield '老冰棍'
    yield '北冰洋'
    yield '牛羊配'
'''
  • yield from 是将列表中的每一个元素返回,所以 如果写两个yield from 并不会产生交替的效果
def func():
    lst1 = ['卫龙', '老冰棍', '北冰洋', '牛羊配']
    lst2 = ['馒头', '花卷', '豆包', '大饼']
    yield from lst1
    yield from lst2


g = func()
for i in g:
    print(i)
# 打印结果 :
'''
卫龙
老冰棍
北冰洋
牛羊配
馒头
花卷
豆包
大饼
'''

yield 与 yield from 对比

  • yield : 对应next 给 next 一 一 返回值
  • yield from : 将迭代对象的每一个元素返回给 next

yield from 作用:

  • 节省代码,提升效率(代替了for循环)

推导式

列表推导式

优点 :

  • 简单 快捷

缺点 :

  • 可读性不高 不好排错
li = []
for i in range(1,101):
    li.append(i)
print(li)
 
li = [i for i in range(1,101)]  #列表推导式(循环模式)
print(li)

构建方式

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

筛选模式 : [变量(加工的变量) for 变量 in iterable if 条件]

# 要求做一个列表 1-100
li = [i for i in range(1,101)]
print(li)
# 要求做一个1-10之内的平方和的列表
li = [i*i for i in range(1,11)]
print(li)
# 1-100内 所有的偶数
li = [i for i in range(1,101) if i % 2 == 0]
print(li)  # 这个就是筛选模式(有条件判断)

li = [i for i in range(2,101,2)]
print(li)

# "python1期"到"python100期"的列表
li = [f'python{i}期' for i in range(1,101)]
print(li)  # f'python{i}',就是加工的变量

多层列表推导式

#找到嵌套列表中名字含有两个‘e’的所有名字(有难度)
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
         ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
li = []
for i in names:
    for e in i:
        if e.count("e") > 1:
            li.append(e)
print(li)

print([e for i in names for e in i if e.count("e") == 2]) # 两层

生成器表达式

  • 节省内存
  • 与列表推导式几乎一模一样,只是把[]换成()就行了

循环模式

gen = (i**2 for i in range(10))
print(gen)
# 结果: <generator object <genexpr> at 0x0000026046CAEBF8>

筛选模式

# 获取1-100内能被3整除的数
gen = (i for i in range(1,100) if i % 3 == 0)
for num in gen:
    print(num) # 打印结果就是for遍历了 所有在gen里的元素
print(next(gen))  # 要几个打印几个 一次只打印一个 记录位置
print(*gen) # 横向打印所有的gen里的元素
print(list(gen))  # 打印一个列表 (list可换成set / tuple / ) 字典除外

如何触发生成器(迭代器)取值

nxet

for / for i in li print(next(li))

print(list(obj)) 直接打印出一个列表 转化成容器类型(字典除外) 常用list转化

print(*obj)

字典推导式 循环模式 / 筛选模式

lst1 = ['jay','jj','meet']
lst2 = ['周杰伦','林俊杰','郭宝元']
dic = {lst1[i]:lst2[i] for i in range(len(lst1))}    # 两个列表长度必须一样
print(dic)

集合推导式 循环模式 / 筛选模式

lst = [1,2,3,-1,-3,-7,9]
s = {abs(i) for i in lst}
print(s) # 天然去重

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

生成器表达式

  • 生成器表达式遵循迭代器协议,逐个产生元素
  • 生成器表达式获取的是一个生成器
  • 生成器表达式只是一个内存地址

列表推导式

  • 列表推导式一目了然
  • 比较耗内存,所有数据一次性加载到内存
  • 得到的值不一样,列表推导式得到的是一个列表.生成器表达式获取的是一个生成器

​ 无论是生成器表达式,还是列表推导式,他只是Python给你提供了一个相对简单的构造方式,因为使用推导式非常简单,所以大多数都会为之着迷,这个一定要深重,推导式只能构建相对复杂的并且有规律的对象,对于没有什么规律,而且嵌套层数比较多(for循环超过三层)这样就不建议大家用推导式构建。

生成器的惰性机制: 生成器只有在访问的时候才取值,说白了.你找他要才给你值.不找他要.他是不会执行的.

原文地址:https://www.cnblogs.com/fanxss/p/11051492.html