python学习 day13_推导式&生成器

python学习 day13

  • 推导式 : 用一行循环判断遍历出一系列数据的方式
  • 列表推导式
    • (1)普通推导式
    • (2)带有判断条件的推到式
    • (3)多循环推到式
    • (4)带有判断条件的多循环推到式
    • 关于推导式的练习
    • (2).把列表中所有字符变成小写 ["ADDD","dddDD","DDaa","sss"]
    • (3).x是0-5之间的偶数,y是0-5之间的奇数 把x,y组成一起变成元组,放到列表当中
      • 方法一
      • 方法二
    • (4).使用列表推导式 制作所有99乘法表中的运算
    • (5).求M,N中矩阵和元素的乘积
      • 第一个效果
      • 第二个效果
  • 集合推导式
  • 字典推导式
    • 【1】enumerate
      • 1.通过推导式配合enumerate创建字典:
      • 2.通过dict 强转字典 实现
    • 【2】zip
      • 1.使用zip配合推导式转入字典
      • 2.通过dict 墙砖字典 实现
  • 生成器
    • 生成器表达式 定义一个生成器
    • yield 类似于 return
      • (1) 基本语法:
      • (2) 优化代码
  • send 可以发送数据,发送给上一个yield
    • yield from : 将一个可迭代对象变成一个迭代器返回
    • 案例: 用生成器来写一个斐波那契数列

推导式 : 用一行循环判断遍历出一系列数据的方式

  • 推导式在使用时,只能用for循环和判断,
    而且判断是能是单项判断

列表推导式

案例:创建一个包含1~50整数的列表
常规写法:

lst_new = []
for i in range(1,51):
	lst_new.append(i)

推导式写法:

lst = [i for i in range(1,51)]

(1)普通推导式

案例:将[1,2,3,4] 转化为 [2,8,24,64]

lst = [1,2,3,4]
# lst = [ i * 2**i for i in lst ]
lst = [i << i for i in lst]		# 将i*2**i简化为i<
print(lst)

(2)带有判断条件的推到式

案例:将列表中的偶数提取组成新的列表
常规写法:

lst = [1,2,3,4,5,6,67,7,8]
lst_new = []
for i in lst:
	if i % 2 == 0:
		lst_new.append(i)
print(lst_new)

推导式改写:

lst = [ i for i in lst if i % 2 == 0 ]
print(lst)

(3)多循环推到式

常规写法:

lst1 = ["王振","黄俊","刘伟"]
lst2 = ["魏小林","刘思敏","陈芮"]
lst_new = []
for i in lst1:
	for j in lst2:
		res = i+"♥"+j
		lst_new.append(res)
print(lst_new)

推导式改写:

lst = [i+"♥"+j for i in lst1 for j in lst2]

(4)带有判断条件的多循环推到式

常规写法:

lst_new = []
for i in lst1:
	for j in lst2:
		if lst1.index(i) == lst2.index(j):
			res = i+"♥"+j
			lst_new.append(res)
print(lst_new)

推导式改写:

lst = [ i+"♥"+j for i in lst1 for j in lst2 if lst1.index(i) == lst2.index(j) ]

关于推导式的练习

(1).{‘x’: ‘A’, ‘y’: ‘B’, ‘z’: ‘C’ } 把字典写成x=A,y=B,z=C的列表推导式
dic = {‘x’: ‘A’, ‘y’: ‘B’, ‘z’: ‘C’ }
常规写法:

for k,v in dic.items():
	res = k + "=" + v
	lst_new.append(res)
print(lst_new)
*推导式改写:**
lst = [ k + "=" + v for k,v in dic.items() ]
print(lst)

(2).把列表中所有字符变成小写 [“ADDD”,“dddDD”,“DDaa”,“sss”]

常规写法:

lst =  ["ADDD","dddDD","DDaa","sss"]
lst_new = []
for i in lst:
	res= i.lower()
	lst_new.append(res)
print(lst_new)

推导式改写:

lst = [i.lower() for i in lst ]
print(lst)

(3).x是0-5之间的偶数,y是0-5之间的奇数 把x,y组成一起变成元组,放到列表当中

方法一

常规写法:

lst_new = []
for x in range(6):
	for y in range(6):
		if x % 2 == 0 and y % 2 == 1:
			res = x,y
			lst_new.append(res)
print(lst_new)

推导式改写:

lst = [ (x,y) for x in range(6) for y in range(6) if x % 2 == 0 and y % 2 == 1 ]

方法二

常规写法:

lst_new = []
for x in range(6):
	if x % 2 == 0:
		for y in range(6):
			if y % 2 == 1:
				res = x,y
				lst_new.append(res)
print(lst_new)

推导式改写:

lst = [ (x,y) for x in range(6) if x % 2 == 0 for y in range(6) if y % 2 == 1 ]
print(lst)

(4).使用列表推导式 制作所有99乘法表中的运算

常规写法:

for i in range(9,0,-1):
	for j in range(1,i+1):
		print("{:d}*{:d}={:2d}".format(i,j,i*j) , end=" ")
	print()

推导式改写:

lst = [ "{:d}*{:d}={:2d}".format(i,j,i*j) for i in range(9,0,-1) for j in range(1,i+1) ]

(5).求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]]

题目思路:

M[0][0] * N[0][0] = 2
M[0][1] * N[0][1] = 4
M[0][2] * N[0][2] = 6

M[1][0] * N[1][0] = 12
M[1][1] * N[1][1] = 15
M[1][2] * N[1][2] = 18

M[2][0] * N[2][0] = 28
M[2][1] * N[2][1] = 32
M[2][2] * N[2][2] = 36
  • 总结: 能控制下标等于控制了最后的结果

第一个效果

lst = [ M[i][j] * N[i][j] for i in range(3) for j in range(3) ]
print(lst)

第二个效果

代码思路:

# [ [] , [] , [] ] 通过推导式遍历出三个新列表
lst = [ [] for i in range(3) ]
print(lst)
  • 外层i动的慢的,里层的j动的快的,所以下标M[i][j]
    在拿出i的时候, 里面的for 循环了三遍 是在一个新的列表当中实现的;

    推导式代码:
lst = [ [M[i][j] * N[i][j] for j in range(3)] for i in range(3) ]
print(lst)

集合推导式

案例:

  • 满足年龄在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}
]

常规写法:

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

推导式改写:
setvar = { 三运运算符 + for i in iterable }

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

字典推导式

【1】enumerate

格式:

  • enumerate(iterable,[start=0])
    功能:
  • 枚举:将索引号和iterable中的值,一个一个拿出来配对组成元组放入迭代器中

参数:

  • iterable: 可迭代性数据 (常用:迭代器,容器类型数据,可迭代对象range)
    start: 可以选择开始的索引号(默认从0开始索引)

返回值:

  • 迭代器
lst = ["吕洞宾","张果老","蓝采和","何仙姑","铁拐李","韩湘子","曹国舅","王文"]
it = enumerate(lst)
# 可以设置开始的索引值 start=5
it = enumerate(lst , start=5)
from collections import Iterable , Iterator
res = isinstance(it,Iterator)
print(res)		# True
# list强转迭代器
res = list(it)
print(res)		# [(5, '吕洞宾'), (6, '张果老'), (7, '蓝采和'), (8, '何仙姑'), (9, '铁拐李'), (10, '韩湘子'), (11, '曹国舅'), (12, '王文')]

1.通过推导式配合enumerate创建字典:

dic = {
      k:v for k,v in enumerate(lst , start=1) }
print(dic)		# {1: '吕洞宾', 2: '张果老', 3: '蓝采和', 4: '何仙姑', 5: '铁拐李', 6: '韩湘子', 7: '曹国舅', 8: '王文'}

2.通过dict 强转字典 实现

dic = dict(enumerate(lst , start=1))
print(dic)

【2】zip

格式:

  • zip(iterable1,iterable2)

功能:

  • 将多个iterable中的值,一个一个拿出来配对组成元组放入迭代器中

返回:

  • 迭代器

特点:

  • 不能匹对的多余值会被舍弃

zip 的基本使用

lst1 = ["黄俊","朱佳怡","王振","魏小林"]
lst2 = ["李博","刘伟","王颖倩"]
lst3 = ["刘思敏","陈芮"]
it = zip(lst1 , lst2 )
# it = zip(lst1 , lst2  ,lst3 ) 
print(isinstance(it,Iterator))

# 用list强转,瞬间拿到里面所有数据
print( list(it) )

1.使用zip配合推导式转入字典

dic = {
     k:v for k,v in  zip(lst1 , lst2 )}
print(dic)

2.通过dict 墙砖字典 实现

dic = dict(zip(lst1 , lst2 ))
print(dic)

生成器

生成器本质是迭代器,允许自定义逻辑的迭代器

迭代器和生成器区别:

  • 迭代器本身是系统内置的.重写不了.而生成器是用户自定义的,可以重写迭代逻辑

生成器可以用两种方式创建:

  • (1)生成器表达式 (里面是推导式,外面用圆括号)
    (2)生成器函数 (用def定义,里面含有yield)
  • 生成器应用在大数据的场景中,按照需求依次取值,
    切记不要直接迭代生成器所有数据
    一旦数据量较大,类似于死循环

生成器表达式 定义一个生成器

gen = (i* 2 for i in range(1,5))
print(gen)		#  at 0x00000281754C6C10> 属于迭代器

用list强转,瞬间拿到所有数据:

res = list(gen)
print(res)

生成器函数

yield 类似于 return

共同点在于:

  • 执行到这句话都会把值返回出去

不同点在于:

  • yield每次返回时,会记住上次离开时执行的位置 , 下次在调用生成器 , 会从上次执行的位置往下走
    而return直接终止函数,每次重头调用.

格式:

  • yield 6 和 yield(6) 2种写法都可以 yield 6 更像 return 6 的写法 推荐使用

from collections import Iterator

(1) 基本语法:

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)


"""
# error
res = next(gen)
print(res)
"""

代码解析:

  • 第一次调用, print(“one”) yield 1 , 记录当前代码执行的状态15行, 把1直接返回,等待下一次调用
    res = 1 print(1)
  • 第二次调用, 从上一次代码的位置继续向下执行,print(“two”) yield 2 , 记录当前代码执行的状态18行 , 把2直接返回,等待下一次调用
    res = 2 print(2)
  • 第三次调用, 从上一次代码的位置继续向下执行,print(“three”) yield 3 , 记录当前代码执行的状态21行 , 把3直接返回,等待下一次调用
    res = 3 print(3)

如果再进行第四次调用,因为没有yield 关键字返回数据, 所以直接报错 StopIteration

(2) 优化代码

def mygen():
	for i in range(1,101):
		yield "我的球衣号码是%s" % (i)

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

for + next 调用生成器:

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 111
	print(res)
	
	res = yield 222
	print(res)
	
	res = yield 333
	print(res)
	
	print("end")


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

# 第一次调用
# 第一次只能默认发送None,因为第一次没有上一个yield
val = gen.send(None)
print(val)

# 第二次调用
val = gen.send(444)
print(val)

# 第三次调用
val = gen.send(555)
print(val)
# 555
# 333
# 第四次调用 error
# val = gen.send(666)
# print(val)

代码解析:
无论是next 还是 send 都可以调用生成器里面的数据
send 不但可以调用,还可以给yield 发送值

  • 第一次调用send , 只能发送None ,因为还没有遇到yield
    代码从上到下执行, print(“start”) 遇到 res = yield 111
    记录当前代码执行的状态3行,把111值返回,等待下一次调用
    外面的val = 111 print(111)

  • 第二次调用send ,把444发送给上一次保存的位置87行
    yield 进行接收 res = 444 3行往下执行 print(444) 遇到 res = yield 222
    记录当前代码执行的状态6行,把222值返回,等待下一次调用
    外面的val = 222 print(222)

  • 第三次调用send ,把555发送给上一次保存的位置6行
    yield 进行接收 res = 555 6行往下执行 print(555) 遇到 res = yield 333
    记录当前代码执行的状态9行,把333值返回,等待下一次调用
    外面的val = 333 print(333)

  • 第四次调用send , 把555发送给上一次保存的位置9行
    yield 进行接收 res = 666 93行往下执行 print(666) print(“end”)
    没有任何yield 返回数据 , 出现StopIteration
    到此程序彻底结束.

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

迭代器生成前后的代码,会在开始迭代的第一次或最后一次调用一次。

def mygen():
	lst = ["魏小林","陈宁波","朱胜"]
	yield from lst
gen = mygen()
print(next(gen))
print(next(gen))
print(next(gen))

案例: 用生成器来写一个斐波那契数列

斐波那契函数: 1 1 2 3 5 8 13 21 34 55 …

def mygen(maxlength):
	a = 0
	b = 1
	
	i = 0
	while i < maxlength:
		# print(b)
		yield b
		# 当前值 = 上上个值 + 上一个值
		a,b = b,a+b
		i+=1

gen = mygen(50)
# 按照需求量进行取值
for i in range(30):
	print(next(gen))

你可能感兴趣的:(之前的江湖,python)