文章目录
推导式
通过一行循环判断,遍历出一系列数据的方式就是推导式
特点:方便,简介,可以实现一些简单的功能
推导式当中只能跟循环和判断(单项分支)
种类中分为三种: 列表推导式,集合推导式,字典推导式
[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) - 返回 : 迭代器
- 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)
- 用两个列表 实现如下字典:
‘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)