Python笔记_13_推导式_集合推导式_字典推导式_生成器

本文深入探讨Python中的推导式与生成器,包括列表、集合及字典推导式的语法与应用,以及如何使用生成器优化代码执行效率。涵盖条件判断、多循环、字典与集合的推导式,以及生成器的基本使用、send、yieldfrom等高级特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

推导式

通过一行循环判断,遍历出一系列数据的方式就是推导式
特点:方便,简介,可以实现一些简单的功能
推导式当中只能跟循环和判断(单项分支)

种类中分为三种: 列表推导式,集合推导式,字典推导式
[val for val in iterable]
{val for val in iterable}
{a:b for a,b in iterable}

基本语法

例:[1,2,3,4] => [2,4,6,8]

lst = [1, 2, 3, 4]
lst2 = []
for i in lst:
    res = i * 2
    lst2.append(res)
print(lst2)
res = [i for i in range(1, 5)]
# 改写
res = [i * 2 for i in range(1, 5)]
print(res)

例:# [1,2,3,4] => [2,8,24,64]
‘’’
1-> 2 乘以2的1次幂
2-> 8 乘以2的2次幂
3 -> 24 乘以2的3次幂
4 -> 64 乘以2的4次幂
‘’’

# 把想要的值 写在for的左侧
res = [i << i for i in range(1, 5)]  # 1 << 1  2 << 2 3 << 3 4<<4
print(res)
带有条件判断的推导式
lst = [1, 2, 3, 4, 5, 6, 67, 7, 8, 98, 9]
lst2 = []
for i in lst:
    if i % 2 == 0:
        lst2.append(i)
print(lst2)

# 推导式写法
res = [i for i in lst if i % 2 == 0]
print(res)
多循环推导式
lst1 = ["邓远文", "舒畅", "易思", "仿真枪"]
lst2 = ["张国成", "王博", "邱玉龙", "苏传红"]
lst = []
for i in lst1:
    for j in lst2:
        res = i + '♥♥♥' + j
        lst.append(res)
print(lst)
# "谁 ♥♥♥ 谁"

res = [i + '♥♥♥' + j for i in lst1 for j in lst2]
print(res)
带有判断条件的多循环推导式
lst1 = ["邓远文", "舒畅", "易思", "仿真枪"]
lst2 = ["张国成", "王博", "邱玉龙", "苏传红"]
lst_new = []
for i in lst1:
    for j in lst2:
        if lst1.index(i) == lst2.index(j):
            strvar = i + '♥♥♥' + j
            lst_new.append(strvar)

print(lst_new)

res = [
    i +
    '♥♥♥' +
    j for i in lst1 for j in lst2 if lst1.index(i) == lst2.index(j)]
print(res)
测试题

求M,N中矩阵和元素的乘积
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]]

# 效果1  # i=> 0 1 2  j=> 0 1 2 i动的慢 j动的块
res = [M[i][j] * N[i][j] for i in range(3) for j in range(3) ]
print(res) #[2, 4, 6, 12, 15, 18, 28, 32, 36]

#=>实现效果2   [    [2, 4, 6], [12, 15, 18], [28, 32, 36]    ]

# [] [] [] 
'''
第一步遍历三个空列表
[ []  for i in range(3)  ]
第二部在空列表里面在写一个推导式遍历对应的元素
[M[i][j] * N[i][j]  for j in range(3)]
'''
res = [   [M[i][j] * N[i][j]  for j in range(3)]  for i in range(3)   ]
print(res) #[[2,4,6], [], []]

集合推导式

例:
满足年龄在18到21,存款大于等于5000 小于等于5500的人,
开卡格式为:尊贵VIP卡老x(姓氏),否则开卡格式为:抠脚大汉卡老x(姓氏)
把开卡的种类统计出来

listvar = [
    {"name": "王家辉", "age": 18, "money": 10000},
    {"name": "王水机", "age": 19, "money": 5100},
    {"name": "王鹏", "age": 20, "money": 4800},
    {"name": "李站", "age": 21, "money": 2000},
    {"name": "李小龙", "age": 180, "money": 20}
]

# res = {'a':1,"b":2,"c":3}
# for i in res:
	# print(i)
setvar = set()
for i in listvar:
    if 18 <= i['age'] <= 21 and 5000 <= i['money'] <= 5500:
        strvar = '尊贵VIP卡老' + i['name'][0]
        setvar.add(strvar)
    else:
        strvar = '抠脚大汉卡老' + i['name'][0]
        setvar.add(strvar)
print(setvar)


# 真值 if 条件表达式 else 假值
# 第一部分 for i in listvar
# 第二部分 三目运算符:"尊贵VIP卡老" + i["name"][0] if 18 <= i['age']<=21 and 5000<=i['money']<=5500 else "抠脚大汉卡老" + i['name'][0]

res = {"尊贵VIP卡老" + i["name"][0] if 18 <= i['age']<=21 and 5000<=i['money']<=5500 else "抠脚大汉卡老" + i['name'][0] for i in listvar}
print(res)

字典推导式

enumerate
  • 语法 :enumerate(iterable,[start=0])
  • 功能 : 枚举 ; 将索引号和iterable中的值,一个一个拿出来配对组成元组放入迭代器中
  • 参数 :
    iterable : 可迭代性数据 (常用:迭代器,容器类型数据,可迭代对象range)
    start : 可以选择开始的索引号(默认从0开始索引)
  • 返回值 : 迭代器
listvar = ["马军强","何键翰","郑国成","境泽年"]
it = enumerate(listvar)
from collections import Iterator,Iterable
print(isinstance(it,Iterator))

# (1) 使用next进行调用
res = next(it)
print(res)
res = next(it)
print(res)

# (2) 使用for 来调用
for i in it:
	print(i)
	
# (3) 用list瞬间得到所有数据
it = enumerate(listvar)
lst = list(it)
print(lst) #[(0, '马军强'), (1, '何键翰'), (2, '郑国成'), (3, '境泽年')]

# 利用enumerate 变成字典推导式
res = {a:b  for a,b in enumerate(listvar)}
print(res)


# 使用dict强转迭代器
res = dict(enumerate(listvar))
print(res)

# start 可以选择从第几个数值开始数数
res = dict(enumerate(listvar,start=14))
print(res)
zip
  • 语法 : zip(iterable, ... ...)
  • 功能 : 将多个iterable中的值,一个一个拿出来配对组成元组放入迭代器中
    iterable: 可迭代性数据 (常用:迭代器,容器类型数据,可迭代对象range)
  • 返回 : 迭代器
  1. zip 自动配对,如果长度超出了,自动舍弃
lst1 = ["许经雄","刘五星","正路","易思"]
lst2 = ["英俊潇洒","疯牛踢躺","柔情似水","抠脚大汉",1,2,3,4]
it = zip(lst1,lst2)
print(isinstance(it,Iterator))

# 使用for 搭配next 进行调用
for i in range(3):
	res = next(it)
	print(res)

for i in it:
	print(i)

# 利用zip实现字典推导式
res = {a:b for a,b  in zip(lst1,lst2)}
print(res)

# 使用dict强转迭代器
res = dict(zip(lst1,lst2))
print(res)
  1. 用两个列表 实现如下字典:

‘hxd’:‘黄熊大’
‘jzl’:‘将周郎’
‘cgt’:‘陈桂涛’
dic1 = {‘hxd’:“胸大”,“jzl”:“牛逼”,“cgt”:“帅气”}
dic2 = {0:“黄熊大”,1:“将周郎”,2:“陈桂涛”}

dic1 = {'hxd':"胸大","jzl":"牛逼","cgt":"帅气"}
dic2 = {0:"黄熊大",1:"将周郎",2:"陈桂涛"}


lst_keys = dic1.keys()
lst_values = dic2.values()

it = zip(lst_keys,lst_values)
print(it)

# 使用字典推导式实现
res = {a:b for a,b in it}
print(res)
# 使用dict强转迭代器实现
it = zip(lst_keys,lst_values)
res = dict(it)
print(res)

生成器 generator

生成器本质是迭代器,允许自定义逻辑的迭代器
迭代器和生成器区别:
迭代器本身是系统内置的.重写不了.而生成器是用户自定义的,可以重写迭代逻辑

生成器可以用两种方式创建:
(1)生成器表达式 (里面是推导式,外面用圆括号)
(2)生成器函数 (用def定义,里面含有yield)

生成器表达式

例 : [1,2,3,4] => [4,8,12,16]


# i << 2 i乘以2的2次幂
from collections import Iterator, Iterable
gen = (i << 2 for i in range(1, 5))
print(gen)
print(isinstance(gen, Iterator))

# (1)使用next进行调用生成器
res = next(gen)
print(res)
res = next(gen)
print(res)
res = next(gen)
print(res)
res = next(gen)
print(res)
# res = next(gen) 小心越界
# print(res)


# (2) 使用for循环调用生成器
gen = (i << 2 for i in range(1, 5))
for i in gen:
    print(i)

# (3) 用for 和next 搭配调用生成器
gen = (i << 2 for i in range(1, 5))
for i in range(2):
    res = next(gen)
    print(res)

生成器函数

(用def定义,里面含有yield)

yield 类似于 return

  • 共同点在于:执行到这句话都会把值返回出去
  • 不同点在于:yield每次返回时,会记住上次离开时执行的位置 , 下次在调用生成器 , 会从上次执行的位置往下走,而return直接终止函数,每次重头调用.
  • yield 6 和 yield(6) 2种写法都可以 yield 6 更像 return 6 的写法 推荐使用
基本使用

如果函数当中包含了yield ,那么这个函数是生成器函数

from collections import Iterator, Iterable

def mygen():
    print("one")
    yield 1
    print("two")
    yield 2
    print("three")
    yield 3


# 初始化生成器函数  => 返回一个生成器对象 ,简称生成器
gen = mygen()
print(isinstance(gen, Iterator))
# 调用生成器
res = next(gen)
print(res)
res = next(gen)
print(res)
res = next(gen)
print(res)
# res = next(gen)
# print(res)
'''
代码解析:
首先初始化生成器函数 返回生成器对象 简称生成器
同过next进行调用

第一次调用时
print(one)
yield 1  记录当前代码执行的位置状态,添加阻塞,暂停在这一行,并返回1,等待下一次调用

第二次调用时候
print(two)
yield 2  记录当前代码执行的位置状态,添加阻塞,暂停在这一行,并返回2,等待下一次调用

第三次调用时候
print(three)
yield 3  记录当前代码执行的位置状态,添加阻塞,暂停在这一行,并返回3,等待下一次调用

第四次调用时
因为没有yield 返回值了 所以直接报错....
'''
优化代码
def mygen():
    for i in range(1, 101):
        yield "我的球衣号码是%d" % (i)


# 初始化生成器函数 返回 生成器对象 简称生成器
gen = mygen()

for i in range(50):
    res = next(gen)
    print(res)


for i in range(30):
    res = next(gen)
    print(res)

send

把值发送给上一个yield

  • next和send区别:
    next 只能取值
    send 不但能取值,还能发送值
  • send注意点:
    第一个 send 不能给 yield 传值 默认只能写None
    最后一个yield 接受不到send的发送值
def mygen():
    print("start")
    res = yield 1
    print(res)

    res = yield 2
    print(res)

    res = yield 3
    print(res)
    print("end")


# 初始化生成器函数 返回生成器
'''
send 在第一次调用的时候,必须给参数None gen.send(None)
是一个硬性要求的语法(因为第一次调用的时候,没有遇到上一个yield)
'''
gen = mygen()
res = gen.send(None)
print(res)
res = gen.send(111)
print(res)
res = gen.send(222)
print(res)
# res = gen.send(333)
# print(res)
'''
第一次调用时 ,必须使用gen.send(None)
print(start)
res = yield 1 记录当前代码执行的位置状态 ,添加阻塞并返回1,等待下一次调用

第二次调用时 ,
send 先发送 , 在返回 , 发送给yield 1 res接收到了111这个值
print(111)
res = yield 2 记录当前代码执行的位置状态 ,添加阻塞并返回2,等待下一次调用

第三次调用时 ,
send 先发送 , 在返回 , 发送给yield 2 res接收到了222这个值
print(222)
res = yield 3 记录当前代码执行的位置状态 ,添加阻塞并返回3,等待下一次调用

第四次调用时,
因为没有yield 继续返回了 ,直接报错,越界错误
如果仍然想要执行后面没走完的代码,比如95 96 ,那么要通过try ... except 异常处理来解决
try:
	lst = [1,2]
	print(lst[99])
except:
	pass
'''
yield from

将一个可迭代对象变成一个迭代器返回

def mygen():
    # yield ["陈桂涛","五金玲","张俊林"]
    yield from ["陈桂涛", "五金玲", "张俊林"]


# 初始化一个生成器函数mygen  返回生成器
gen = mygen()
res = next(gen)
print(res)
res = next(gen)
print(res)
res = next(gen)
print(res)
用生成器写斐波那契数列
# 1,1,2,3,5,8,13,21.......
def mygen(n):
    a = 0
    b = 1
    i = 0
    while i < n:
        # print(b)
        yield b
        a, b = b, a + b
        i += 1


gen = mygen(100000)
for i in range(20):
    res = next(gen)
    print(res)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值