推导式(列表, 集合, 字典), 生成器

1,  推导式:  通过一行循环判断,遍历出一系列数据的方式是推导式, 推导式在循环时,只能用for循环和单项判断

1.1  列表推导式:   普通推导式,   带有判断条件的推到式 ,  多循环推到式,   带有判断条件的多循环推到式

list1 = [i for i in range(10)]
print(list1)  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]  普通推导式

list2 = [i for i in range(10) if i % 2 == 0]
print(list2)  # [0, 2, 4, 6, 8]   带有条件的推导式

list3 = [("{}*{}={}".format(i,j,i*j)) for i in range(1,10) for j in range(1,i+1)]
print(list3)   # 打印99乘法表添加到列表里  多循环推导式

list4 = [(a,b) for a in range(6) for b in range(6) if a % 2 ==0 and b % 2 ==1]
print(list4)  # [(0, 1), (0, 3), (0, 5), (2, 1), (2, 3), (2, 5), (4, 1), (4, 3), (4, 5)]  带有条件判断的多循环表达式

# 案例:
m = [[1,2,3],[4,5,6],[7,8,9]]
n = [[2,2,2],[3,3,3],[4,4,4]]
# =>实现效果1   [2, 4, 6, 12, 15, 18, 28, 32, 36]
# =>实现效果2   [[2, 4, 6], [12, 15, 18], [28, 32, 36]]
# 效果一:
list5 = [m[i][j]*n[i][j] for i in range(3) for j in range(3)]
print(list5) # [2, 4, 6, 12, 15, 18, 28, 32, 36]

# 效果二:
list6 = [[m[i][j]*n[i][j] for i in range(3)] for j in range(3)]
print(list6) # [[2, 12, 28], [4, 15, 32], [6, 18, 36]]

1.2 集合推导式,遵从列表推导式的语法,注意集合的去重和无序

# (2) 集合推导式:
list1 = ["牛肉","羊肉","米饭","面条","青菜","生菜","米饭","面条"]
set1 = {i for i in list1}
print(set1) # 注意集合的去重性

1.3 字典推导式: 与enumerate配合使用 ,与zip配合使用

                          enumerate()将索引和迭代器中的值配对,组成元祖,返回迭代器,用start可以选择开始的索引号

# 方式一:
list1 = ["天空","白云","大地","小草","大树"]
dict1 = dict(enumerate(list1,start=1))
print(dict1) # {1: '天空', 2: '白云', 3: '大地', 4: '小草', 5: '大树'}

dict1 = dict(enumerate(list1))  #  如果不设置start的话默认从索引0开始
print(dict1) # {0: '天空', 1: '白云', 2: '大地', 3: '小草', 4: '大树'}

# 方式二:
list1 = ["天空","白云","大地","小草","大树"]
dict2 = {k:v for k,v in enumerate(list1,1)}  # start可以不写
print(dict2) # {1: '天空', 2: '白云', 3: '大地', 4: '小草', 5: '大树'}

                     zip()将可迭代对象中的值一个个拿出来配对,组成元祖,返回迭代器,可迭代对象可以放多个,容器中不能配对的值将会被舍弃

list1 = ["天空","白云","大地","小草","大树","飞鸟"]
list2 = ["蓝色","白色","褐色","绿色","翠绿"]
list3 = ["无穷","造雨","生长"]
it = zip(list1,list2,list3)
list4 = list(it)
print(list4)
# [('天空', '蓝色', '无穷'), ('白云', '白色', '造雨'), ('大地', '褐色', '生长')] 
# 以最短的迭代对象为长度配对,其余容器中多余的就会被舍弃
list1 = ["小学","初中","高中","大学"]
list2 = ["小学生","初中生","高中生","大学生"]
# 方式一:
dict1 = dict(zip(list1,list2))
print(dict1) # {'小学': '小学生', '初中': '初中生', '高中': '高中生', '大学': '大学生'}

# 方式二:
dict1 = {k:v for k,v in zip(list1,list2)}
print(dict1) # {'小学': '小学生', '初中': '初中生', '高中': '高中生', '大学': '大学生'}

2. 生成器: 生成器的本质是迭代器,是一个允许自定义的迭代器

                 生成器的创建有两种方式:一是通过生成器表达式(外面是圆括号,里面是表达式),二是通过生成器函数(用def定义函数,函数体内含有yield关键字)

gen = (i+2 for i in range(10) if i % 2 == 0) # 生成器表达式
list1 = list(gen)
print(list1)

通过生成器函数创建:  包含yield关键字的函数才是生成器函数,yield和return一样,都可以把值返回出去,但是yield在返回时,会记住上次执行的位置,下次再调用生成器的时候会从上次执行的地方往下运行

def gen_func():
    print("one")
    yield 1
    print("two")
    yield 2
    print("three")
    yield 3
gen = gen_func()
res = next(gen)
print(res)
# one
# 1
res = next(gen)
print(res)
# two
# 2
res = next(gen)
print(res)
# three
# 3     如果第四次再调用的话,因为没有yield关键字返回数据,所以程序会报错

  生成器中使用send:  生成器中使用send, send不仅可以取值,也可以发送值,

                                  注意:第一个send不能给yield传值,默认发送None,最后一个yield接收不到send发送的值

def mygen():
    print("第一个")
    res = yield "早上"
    print(res)
    res = yield "中午"
    print(res)
    res = yield "晚上"
    print("晚上没有yield了,不用吃饭了") # 打印不出来
gen = mygen()
res = gen.send(None)
print(res)
# 第一个
# 早上
res = gen.send("早餐")
print(res)
# 早餐
# 中午
res = gen.send("午餐")
print(res)
# 午餐
# 晚上

      可迭代对象中使用yield from可以将这个可迭代对象变成生成器

def func1():
    list1 = range(100)
    yield from list1
it = func1()
for i in range(3):
    res = next(it)
    print(res)

  小案例:  用生成器打印斐波那契数列, 1 1 2 3 5 8 13 21 34 55 .....

# 斐波那契数列
def mygen(n):
    a = 0
    b = 1
    i = 0
    while i < n:
        yield b
        a,b = b,a+b
        i += 1
gen = mygen(50)
for i in range(10):
    res = next(gen)
    print(res)

 

posted on 2020-05-16 18:05  fdsimin  阅读(238)  评论(0编辑  收藏  举报