python-列表_集合_字典推导式_生成器

推导式

1. 列表推导式

推导式 : 通过一行循环判断,遍历一系列数据的方式

语法结构 :

​ val for val in Iterable

​ 三种方式:

​ [val for val in Iterable]

​ {val for val in Iterable}

​ {k:v for k,v in Iterable}

# 列表里面需要100条数据
lst = []
for i in range(1,101):
	lst.append(i)
print(lst)

# 基本语法
lst = [i for i in range(1,101)]
print(lst)
  1. 单循环推导式 [1,2,3,4,5] -> [3,6,9,12,15]

    # 常规写法
    lst = [1,2,3,4,5]
    lst_new = []
    for i in lst:
    	res = i * 3
    	lst_new.append(res)
    print(lst_new)
    
    # 改成推导式
    lst = [i*3 for i in lst]
    print(lst)
    
  2. 带有判断条件的单循环推导式 (只能是单项分值,接在for后面)

    # 常规写法
    lst = [1,2,3,4,5,6,7,8,9]
    lst_new = []
    for i in lst:
    	if i % 2 == 1:
    		lst_new.append(i)
    print(lst_new) 
    
    # 改成推导式
    lst = [i for i in lst if i % 2 == 1]
    print(lst)
    
  3. 双循环推导式

    # 常规写法
    lst1 = ["刘德华","周星驰","张学友","梁朝伟"]
    lst2 = ["郑秀文","朱茵","张家辉","刘嘉玲"]
    # 谁 "❤" 谁
    lst_new = []
    for i in lst1:
    	for j in lst2:
    		strvar = i + "❤" + j
    			lst_new.append(strvar)
    print(lst_new)
    
    # 改成推导式
    lst = [i + "❤" + j for i in lst1 for j in lst2]
    print(lst)
    
  4. 带有判断条件的多循环推导式

    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)
    
    # 改成推导式
    lst = [i + "❤" + j for i in lst1 for j in lst2 if lst1.index(i) == lst2.index(j)]
    print(lst)
    

推导式练习

练习1

{‘x’: ‘A’, ‘y’: ‘B’, ‘z’: ‘C’ } 把字典写成x=A,y=B,z=C的列表推导式

# 常规写法 
dic = {'x': 'A', 'y': 'B', 'z': 'C' }
lst = []
for k,v in dic.items():
	strvar = k + "=" + v
	lst.append(strvar)
print(lst)

# 改写成推导式
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:
	lst_new.append(i.lower())	
print(lst_new)	

# 改写成推导式
lst = [i.lower() for i in lst]
print(lst)

练习3

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

"""
x : 0 2 4
y : 1 3 5
"""
# 方法一
# 常规写法
lst = []
for x in range(6):
	for y in range(6):
		if x % 2 == 0 and y % 2 == 1:
			lst.append((x,y))
print(lst)	

# 改写成推导式
lst = [(x,y) for x in range(6) for y in range(6) if x % 2 == 0 and y % 2 == 1]
print(lst)

# 方法二
# 常规写法
lst = []
for x in range(6):
	if x % 2 == 0:
		for y in range(6):
			if y % 2 == 1:
				lst.append((x,y))
print(lst)	

# 改写成推导式
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("{}*{}={:2d} ".format(i,j,i*j),end="")
	print()

# 改写成推导式
lst =["{}*{}={:2d} ".format(i,j,i*j) for i in range(9,0,-1) for j in range(1,i+1)]
print(lst)

练习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 = [[1,2,3],[4,5,6],[7,8,9]]
N = [[2,2,2],[3,3,3],[4,4,4]]
"""
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

外层循环动的慢,内层循环动得快
外层循环动一次,内层循环动3次
利用这个规律取出对应下标,乘积即可
"""
# 效果一
# 常规写法
lst = []
for i in range(3):
	for j in range(3):
		# print(i,j)
		# res = M[i][j] * N[i][j]
		# lst.append(res)
		lst.append(M[i][j] * N[i][j])
print(lst)		

# 改写成推导式
lst = [M[i][j] * N[i][j] for i in range(3) for j in range(3)]
print(lst)

# 效果二
# 常规写法
M = [[1,2,3],[4,5,6],[7,8,9]]
N = [[2,2,2],[3,3,3],[4,4,4]]
lst = []
for i in range(3):
	lst2 = []
	for j in range(3):
		lst2.append(M[i][j] * N[i][j])
	lst.append(lst2)	
print(lst)	

# 改写成推导式
# 1. 先遍历出三个空列表
lst = [ [] for i in range(3) ] 
"""=> [ [] , [] , [] ]"""
# 2. 把空列表中的数据再通过推导式算出所有内容
lst = [ [M[i][j] * N[i][j] for j in range(3)] for i in range(3) ]
print(lst)

2. 集合推导式

案例 :

​ 满足年龄在18到21,存款大于等于5000,小于等于5500的人

​ 开卡格式: 尊贵VIP卡老x(姓氏),否则开卡格式为:抠脚大汉卡老x(姓氏)

​ 把开卡的种类统计出来

listvar = [
    {"name":"李鑫炜","age":18,"money":8888},
	{"name":"刘聪","age":19,"money":5200},
	{"name":"刘子豪","age":20,"money":4666},
	{"name":"孔祥群","age":21,"money":2222},
	{"name":"宋云杰","age":18,"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 = { "尊贵VIP卡老" + i["name"][0] if 18 <= i["age"] <= 21 and 5000 <= i["money"] <= 5500 else  "抠脚大汉卡老" + i["name"][0] for i in listvar }
print(setvar)

3. 字典推导式

1. enumerate 列举 枚举

语法结构 : enumerate(iterable,[start=0])

功能 :

​ 枚举 ,将索引号和 iterable 中的值,一个一个拿出来配对组成元组放入迭代器中

参数 :

​ iterable : 可迭代性数据 (迭代器 , 容器类型数据 , 可迭代对象range)

​ start : 可以选择开始的索引号(默认从0开始索引)

返回值 :

​ 迭代器

from collections import Iterator
lst = ["东邪","西毒","南帝","北丐"]

# 基本使用
it = enumerate(lst)
print(isinstance(it,Iterator))

# for + next
for i in range(4):
	print(next(it))

"""start可以指定开始值,默认是0"""    
# list 强转成列表
it = enumerate(lst,start=1)
print(list(it))

# enumerate 形成字典推导式 变成字典
dic = {k:v for k,v in enumerate(lst,start=1)}
print(dic)

# dict 强转变成字典
dic = dict(enumerate(lst,start=1))
print(dic)

2. zip 拉链式

语法结构 : zip(iterable, … …)

功能 :

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

参数 :

​ iterable : 可迭代性数据 (迭代器 , 容器类型数据 , 可迭代对象range)

返回值 :

​ 迭代器

特征 :

​ 如果找不到对应配对的元素,当前元素会被舍弃

from collections import Iterator
# 基本使用
lst1 = ["苏大强","小明","小花","小蔡","小新"]
lst2 = ["苏明成","小小明","大花","小保姆"]
lst3 = ["苏明玉","小明明","小花花"]
it1 = zip(lst1,lst2)
it2 = zip(lst1,lst2,lst3)
print(isinstance(it1,Iterator))
print(list(it1))
print(list(it2))

# zip 形成字典推导式 变成字典
lst1 = ["苏大强","小明","小花","小蔡","小新"]
lst2 = ["苏明成","小小明","大花","小保姆"]
dic = {k:v for k,v in zip(lst1,lst2)}
print(dic)

# dict 强制变成字典
dic = dict(zip(lst1,lst2))
print(dic)

生成器

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

迭代器与生成器的区别 :

​ 迭代器本身是系统内置的, 重写不了, 比如zip , enumerate …

​ 生成器是用户自定义的,可以重写迭代逻辑

生成器的两种创建方式 :

1. 生成器表达式 (里面是推导式,外面用圆括号)
	2. 生产器函数     (用def定义,里面含有yield) 

1. 生成器表达式

from collections import Iterator,Iterable

gen = (i*2 for in range(1,11))
print(isinstance(gen,Iterator))

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

# for 
for i in gen:
	print(i)

# for + next
gen = (i*2 for in range(1,11)) 
for i in range(3):
	res = next(gen)
	print(res)

# list    
res = list(gen)
print(res)

2. 生成器函数

yield 类似于 return

共同点 : 执行到这句话都会把值返回出去

不同点 : yield 每次返回时,会记住上次离开时执行的位置,下次再调用生成器,会从上次执行的位置往下走

​ 而return直接终止函数,每次重头调用

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

  1. 生成器函数的基本语法

    from collections import Iterator ,Iterable
    """定义一个生成器函数"""
    def mygen():
    	print(111)
    	yield 1
    	
    	print(222)
    	yield 2
    	
    	print(333)
    	yield 3
    	
    """初始化生成器函数,返回生成器对象,简称生成器"""
    gen = mygen()
    print(isinstance(gen,Iterator))
    
    # 使用next调用
    res = next(gen)
    print(res)
    res = next(gen)
    print(res)
    res = next(gen)
    print(res)
    # res = next(gen) error
    # print(res)
    
    """
    代码解析 : 
    初始化生成器函数 -> 生成器(通过next调用)
    第一次调用生成器
    res = next(gen) => print(111) yield 1 保存当前代码状态到第5行,并将1这个值返回 print(1),等待下一次调用
    第二次调用生成器
    res = next(gen) => 从上一次保存的状态第5行继续向下执行
    print(222) yield 2 保存当前代码状态8行,并将2这个值返回 print(2),等待下一次调用
    第三次调用生成器
    res = next(gen) => 从上一次保存的状态第8行继续向下执行
    print(333) yield 3 保存当前代码状态11行,并将3这个值返回 print(3),等待下一次调用
    第四次调用生成器
    因为没有更多的yeild返回数据了,所有直接报错
    """
    
  2. 优化代码

    def mygen():
    	for i in range(1,101):
    		yield "该球衣号码是{}".format(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)
    
  3. send 用法

    send 和 next 的区别 :

    ​ next 只能取值

    ​ send 不但能取值,还能发送值

    send 注意点 :

    ​ 第一个 send 不能给 yield 传值 , 默认只能写 None

    ​ 最后一个 yield 接收不到 send 的发送值

    ​ send 是给上一个 yield 发送值

    def mygen():
    	print("process start")
    	res = yield 100
    	print(res,"100个俯卧撑")
    	
    	res = yield 200
    	print(res,"200个俯卧撑")
    	
    	res = yield 300
    	print(res,"300个俯卧撑")
    	print("process end")
    
    """初始化生成器函数 -> 生成器"""	
    gen = mygen()
    
    """在使用send时,第一次调用必须传递的参数是None(硬性语法),因为第一次还没有遇到上一个yield"""
    
    """第一次调用"""
    res = gen.send(None) # <=> next(gen)
    print(res)
    
    """第二次调用"""
    res = gen.send(101) # <=> next(gen)
    print(res)
    
    """第三次调用"""
    res = gen.send(201) # <=> next(gen)
    print(res)
    
    """
    第四次调用
    因为没有更多的yield返回数据了,所有代码 StopIteration
    res = gen.send(201) # <=> next(gen)
    print(res)
    """
    
    """
    代码解析 : 
    初始化生成器函数,返回生成器对象
    第一次调用时,
    print("process start")
    res = yield 100 记录当前代码状态,返回100,等待下一次调用
    res = 100 print(100)
    
    第二次调用时,
    把 101 发送给上一个 yield 保存的状态 res = 101 从当前代码行继续向下执行
    print(101,"100个俯卧撑")
    res = yield 200 记录当前代码状态,返回200,等待下一次调用
    res = 200 print(200)
    
    第三次调用时,
    把 201 发送给上一个 yield 保存的状态 res = 201 从当前代码行继续向下执行
    print(201,"200个俯卧撑")
    res = yield 300 记录当前代码转态,返回300,等待下一次调用
    res = 300 print(300)
    """
    
  4. yield from : 将一个可迭代对象变成一个迭代器返回

    def mygen():
    	yield ["小明","小红","小花","小草"]
    
    """初始化生成器函数 -> 生成器"""		
    gen = mygen()
    print(next(gen))
    
    def mygen():
    	yield from ["小明","小红","小花","小草"]
    
    gen = mygen()
    print(next(gen))
    print(next(gen))
    print(next(gen))
    print(next(gen))
    
  5. 用生成器描述裴波那契数列

    裴波那契数列 : 1 1 2 3 5 8 13 21 34 …

    """
    yield 1
    a,b = b,a+b = 1,1
    
    yield 1
    a,b = b,a+b = 1,2
    
    yield 2
    a,b = b,a+b = 2,3
    
    yield 3
    a,b = b,a+b = 3,5
    
    ...
    
    """
    
    def mygen(maxlen):
    	a,b = 0,1
    	i = 0
    	while i < maxlen:
    		yield b
    		a,b = b,a+b
    		i+=1
    
    """初始化生成器函数 -> 生成器"""	
    gen = mygen(21)
    
    for i in range(9):
    	print(next(gen))
    
    print("<=========>")    
        
    for i in range(5):
    	print(next(gen))
    

练习

1.用推导式写如下程序

(1)构建如下列表:[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

lst = [i for i in range(0,19,2)]
print(lst)

(2)lst = [‘alex’, ‘WuSir’, ‘老男孩’, ‘神秘男孩’] 将lst构建如下列表:[‘alex0’, ‘WuSir1’, ‘老男孩2’, ‘神秘男孩3’]

lst = ['alex', 'WuSir', '老男孩', '神秘男孩']
lst = [lst[i] + str(i) for i in range(4)]
print(lst)

(3)构建如下列表:[(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]

lst = [(i,i+1) for i in range(6)]
print(lst)

(4)求出50以内能被3整除的数的平方,并放入到一个列表中

lst = [i ** 2 for i in range(51) if i % 3 == 0]
print(lst)

(5)M = [[1,2,3],[4,5,6],[7,8,9]], 把M中3,6,9组成新列表

M = [[1,2,3],[4,5,6],[7,8,9]]
# 方法一
lst = [ M[i][2] for i in range(3) ]
print(lst)
# 方法二
lst = [ i[-1]] for i in M ]
print(lst)
# 方法三
lst = [ j for i in M for j in i if i.index(j) == 2 ]
print(lst)

(6)构建如下列表:[‘python1期’, ‘python2期’, ‘python3期’, ‘python4期’, ‘python6期’, ‘python7期’, ‘python8期’, ‘python9期’, ‘python10期’]

lst = [ "python{}期".format(i) for i in range(1,11) if i != 5 ]
print(lst)

(7)过滤掉长度小于3的字符串列表 , 并转换成大写字母

lst = [ "abcdefg","it","li","cderuty","cute","pop" ]
lst = [ i.upper() for i in lst if len(i) > 2 ]
print(lst)

(8)除了大小王,里面有52项,每一项是一个元组,请返回如下扑克牌列表[(‘红心’,‘2’),(‘草花’,‘J’), …(‘黑桃’,‘A’)]

lst1 = ["红桃","黑桃","梅花","方片"]
lst2 = ["A","2","3","4","5","6","7","8","9","10","J","Q","K"]
lst = [ (i,j) for i in lst1 for j in lst2 ]
print(lst)

2.用推导式写如下程序

lst1 = {
		'name':'alex',
		'Values':[
			{'timestamp': 1517991992.94,'values':100,},			 
			{'timestamp': 1517992000.94,'values': 200,},			
			{'timestamp': 1517992014.94,'values': 300,},			 
			{'timestamp': 1517992744.94,'values': 350},			 
			{'timestamp': 1517992800.94,'values': 280}			 
		]
	}
# 将lst1 转化成如下lst2:
lst2 = [
	[1517991992.94, 100], 
	[1517992000.94, 200], 
	[1517992014.94, 300], 
	[1517992744.94, 350], 
	[1517992800.94, 280]
]

# 方法一
lst = [ [i["timestamp"],i["values"]] for i in lst1["Values"] ]
print(lst)
# 方法二
lst = [ [ j for j in i.values() ] for i in lst1["Values"] ]
print(lst)

3.读取一个文件所有内容,通过生成器调用一次获取一行数据

from collections import Iterator,Iterable
# 生成器函数
def func():
	with open("ceshi1",mode="r+",encoding="utf-8") as fp:
		# fp 是迭代器(一次成文件中拿取一行数据)
		# print(isinstance(fp,Iterator))
		for i i fp:
			yield i
# 通过初始化返回生成器
gen = func()
# for next list 在获取迭代器中的数据时,才会调用其中的内容
res = next(gen)
print(res)
res = next(gen)
print(res)
res = next(gen)
print(res)

4.将普通求和函数改写成yield写法

# 常规写法
def add(a,b):                     
    return a + b
# yield 写法
def mygen(a,b):
	yield a + b
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

I believe I can fly~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值