推导式通过一行循环判断遍历出一些列数据的方法叫做推导式
语法:
val for val in iterable
1.推导式基本语法lst = []for i in range(1,51):lst.append(i)print(lst)改写推导式
lst = [i for i in range(1,51)]print(lst)小练习
# 1.[1,2,3,4,5] => [2,4,6,8,10]lst = [ i*2 for i in range(1,6) ]print(lst)2.带有判断条件的推导式注意点:for后面紧跟的判断条件只能是单项分支.
[1,2,3,4,5,6,7,8,9,10] => [1,3,5,7,9 ... ]
lst = [1,2,3,4,5,6,7,8,9,10]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:lst_new.append(i+"????"+j)print(lst_new)改写推导式
lst = [ i+"????"+j for i in lst1 for j in lst2 ]print(lst4.带有判断条件的多循环推导式lst_new = []for i in lst1:for j in lst2:if lst1.index(i) == lst2.index(j):lst_new.append(i+"????"+j)print(lst_new)改写推导式
lst = [i+"????"+j for i in lst1 for j in lst2 if lst1.index(i) == lst2.index(j)]print(lst)集合推导式案例:
满足年龄在18到21,存款大于等于5000 小于等于5500的人,
开卡格式为:尊贵VIP卡老x(姓氏),否则开卡格式为:抠脚大汉卡老x(姓氏)
把开卡的种类统计出来
lst = [{"name":"赵沈阳","age":18,"money":3000},{"name":"赵万里","age":19,"money":5200},{"name":"赵蜂拥","age":20,"money":100000},{"name":"赵世超","age":21,"money":1000},{"name":"王志国","age":18,"money":5500},{"name":"王永飞","age":99,"money":5500}]setvar = set()for i in lst:print(i) # {'name': '赵沈阳', 'age': 18, 'money': 3000}if 18 <= i["age"] <= 21 and 5000 <= i["money"] <= 5500:res = "尊贵VIP卡老{}".format(i["name"][0])else:res = "抠脚大汉卡老{}".format(i["name"][0])# 添加到集合中setvar.add(res)print(setvar){ 三元运算符 + 推导式 }
setvar = { "尊贵VIP卡老{}".format(i["name"][0]) if 18 <= i["age"] <= 21 and 5000 <= i["money"] <= 5500 else "抠脚大汉卡老{}".format(i["name"][0]) for i in lst }print(setvar)字典推导式一.enumerateenumerate(iterable,[start=0])
功能:枚举 ; 将索引号和iterable中的值,一个一个拿出来配对组成元组,通过迭代器返回
参数:
iterable: 可迭代性数据 (常用:迭代器,容器类型数据,可迭代对象range)
start:可以选择开始的索引号(默认从0开始索引)
返回值:迭代器
基本语法
from collections import Iterator,Iterablelst =["王文","吕洞宾","何仙姑","铁拐李","张国老","曹国舅","蓝采和","韩湘子"]it = enumerate(lst)it = enumerate(lst,start=100)print(isinstance(it,Iterator))next
print( next(it) )for + next (推荐,数据较大时使用)
for i in range(3):print(next(it))for
for i in it:print(i)list 强转迭代器
print(list(it))(1) 字典推导式 配合 enumerate 来实现
dic = {k:v for k,v in enumerate(lst,start=100)}print(dic)"""(100, '王文')(101, '吕洞宾')(102, '何仙姑')(103, '铁拐李')(104, '张国老')(105, '曹国舅')(106, '蓝采和')(107, '韩湘子')"""(2) 使用dict强转迭代器,瞬间得到字典
dic = dict( enumerate(lst,start=100) )print(dic)二.zip特点:按照索引配对
zip(iterable, ... ...)
功能: 将多个iterable中的值,一个一个拿出来配对组成元组,通过迭代器返回
iterable: 可迭代性数据 (常用:迭代器,容器类型数据,可迭代对象range)
返回: 迭代器
基本语法
# lst1 = ["孙开启","王永飞","于朝志"]# lst2 = ["薛宇健","韩瑞晓","上朝气"]# lst3 = ["刘文博","历史园","张光旭"]# 在索引下标同时存在时,才会进行配对,否则舍弃.lst1 = ["孙开启","王永飞","于朝志"]lst2 = ["薛宇健","韩瑞晓"]lst3 = ["刘文博"]it = zip(lst1,lst2,lst3)print(list(it))(1) 字典推导式 配合 zip 来实现
lst_key = ["ww","axd","yyt"]lst_val = ["王维","安晓东","杨元涛"]# ('ww', '王维'), ('axd', '安晓东'), ('yyt', '杨元涛')dic = {k:vfor k,v in zip(lst_key , lst_val) }print(dic)(2) 使用dict强转迭代器,瞬间得到字典
dic = dict( zip(lst_key , lst_val) )print(dic) 生成器生成器本质是迭代器,允许自定义逻辑的迭代器
迭代器和生成器区别:
迭代器本身是系统内置的.重写不了.
而生成器是用户自定义的,可以重写迭代逻辑
生成器可以用两种方式创建:
(1)生成器表达式(里面是推导式,外面用圆括号)
(2)生成器函数(用def定义,里面含有yield)
(1) 生成器表达式 (里面是推导式,外面用圆括号)
gen = ( i for i in range(10) )print(gen) 判断类型from collections import Iterator,Iterableprint(isinstance(gen,Iterator))1.next 调用生成器print(next(gen))print(next(gen))2.for + next 调用生成器for i in range(3):print(next(gen))3.for 调用生成器所有数据for i in gen:print(i)4.list强转生成器,瞬间得到所有数据gen = ( i for i in range(10) )print(list(gen))# print(next(gen)) error# StopIteration生成器函数yield 类似于 return
共同点在于:执行到这句话都会把值返回出去
不同点在于:yield每次返回时,会记住上次离开时执行的位置 , 下次在调用生成器 , 会从上次执行的位置往下走,而return直接终止函数,每次重头调用.
yield 6 和 yield(6) 2种写法都可以 yield 6 更像 return 6 的写法 推荐使用
(1) 基本语法def mygen():print("111")yield 1print("222")yield 2print("333")yield 3# 初始化生成器函数=> 返回生成器对象 => 简称生成器gen = mygen()# 第一次调用res = next(gen)print(res)# 第二次调用res = next(gen)print(res)# 第三次调用res = next(gen)print(res)# 第四次调用"""StopIteration error res = next(gen)print(res)""""""# 第一次调用print("111")yield 1 保存当前第13行代码的状态,把1返回,并且等待下一次调用# 第二次调用从上一次保存的位置13行往下走, print("222") yield 2 保存当前第16行代码的状态,把2返回,并且等待下一次调用# 第三次调用从上一次保存的位置16行往下走, print("333") yield 3 保存当前第19行代码的状态,把3返回,并且等待下一次调用# 第四次调用因为没(2) 优化生成器代码生成器应用的场景是在大数据的范围中使用,切记不可直接用for遍历所有,可能无法短时间内获取所有数据
def mygen():for i in range(1,101):yield i# 初始化生成器函数 => 生成器gen = mygen()print("<=====>")for i in range(30):num = next(gen)print("我的球衣号码是{}".format(num))print("<=====>")for i in range(40):num = next(gen)print("我的球衣号码是{}".format(num))(3) 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")# 初始化生成器函数 => 生成器gen = mygen()# 第一次调用生成器"""第一次调用生成器时,因为没有遇到yield保存的代码位置,无法发送数据,默认第一次只能发送None"""res = gen.send(None)print(res,"<==外部==>")# 第二次调用生成器res = gen.send("100")print(res,"<==外部==>")# 第三次调用生成器res = gen.send("200")print(res,"<==外部==>")# 第四次调用生成器"""errorres = gen.send("300")print(res,"<==外部==>")""""""使用send调用生成器,第一次发送时必须是None,因为还没有遇到yield保存的代码位置res = gen.send(None)走到mygen生成器函数中print("start") res = yield "内部1"执行第80行 ,保存退出,记录当前代码位置,将 "内部1" 返回在98行接受数据res = "内部1"print(内部1,"<==外部==>")第二次调用生成器res = gen.send("100") 把100这个数据发送给上一次代码保存的位置80行进行接受. => 导致 80行 res = 100打印81行print(100 ,"<==内部==>")执行83行res = yield "内部2"保存退出,记录当前代码位置,将 "内部2" 返回执行102行 res = gen.send("100") => "内部2" print("内部2","<==外部==>")....依次类推 ... 到第四次调用时, 因为没有更多的yield 返回数据,gen.send(300)无法接受到返回值,所以出现停止迭代 StopIteration的报错,程序终止;"""(4) yield from 的使用将一个可迭代对象变成一个迭代器返回
def mygen():lst = ["张磊","李亚峰","刘一峰","王同培"]yield from lst# 初始化生成器函数gen = mygen()print(next(gen))print(next(gen))print(next(gen))print(next(gen))# print(next(gen)) # StopIteration(5) 斐波那契数列"""使用生成器分段获取所有内容,而不是一股脑的把所有数据全部打印"""
"""1 1 2 3 5 8 13 21 34 .... """
def mygen(maxval):a,b = 0,1i = 0while i < maxval:# print(b)yield ba,b = b,a+bi += 1# mygen(10)gen = mygen(10)# 第一次获取for i in range(3):print(next(gen))# 第二次获取for i in range(5):print(next(gen))递归函数递归函数 : 自己调用自己的函数 , 叫做递归函数
递 : 去
归 : 回
一去一回叫做递归
def digui(n):print(n,"<==1==>")if n > 0:digui(n-1)print(n,"<==2==>")digui(5)"""# 去的过程n = 5 print(5,"<==1==>")if 5 > 0:digui(5-1) =>digui(4) 代码阻塞在第12行n = 4 print(4,"<==1==>")if 4 > 0:digui(4-1) =>digui(3) 代码阻塞在第12行n = 3 print(3,"<==1==>")if 3 > 0:digui(3-1) =>digui(2) 代码阻塞在第12行n = 2 print(2,"<==1==>")if 2 > 0:digui(2-1) =>digui(1) 代码阻塞在第12行n = 1 print(1,"<==1==>")if 1 > 0:digui(1-1) =>digui(0) 代码阻塞在第12行n = 0 print(0,"<==1==>")if 0 > 0: 不成立 print(0,"<==2==>") 到此最后一层函数空间彻底执行完毕# 回的过程回到上一层函数空间n = 1 代码在第12行的位置,继续往下执行print(1,"<==2==>")回到上一层函数空间n = 2 代码在第12行的位置,继续往下执行print(2,"<==2==>")回到上一层函数空间n = 3 代码在第12行的位置,继续往下执行print(3,"<==2==>")回到上一层函数空间n = 4 代码在第12行的位置,继续往下执行print(4,"<==2==>")回到上一层函数空间n = 5 代码在第12行的位置,继续往下执行print(5,"<==2==>")到此递归函数执行结束..打印 543210012345""""""每次调用函数时,都要单独在内存当中开辟空间,叫做栈帧空间,以运行函数中的代码递归总结:(1)递归实际上是不停的开辟栈帧空间和释放栈帧空间的过程,开辟就是去的过程,释放就是回的过程(2)递归什么时候触发归的过程:1.当最后一层栈帧空间执行结束的时候,触发归的过程.2.当遇到return返回值的时候终止当前函数,触发归的过程.(3)递归不能无限的去开辟空间,可能造成内存溢出,蓝屏死机的情况,所以一定要给予跳出的条件(如果递归的层数太大,不推荐使用)(4)开辟的一个个栈帧空间,数据是彼此独立不共享的."""流程解析

文章插图
递归原理图:

文章插图
递归不能不限开辟空间
官方说法最大默认是1000层
def deepfunc():deepfunc()deepfunc()1.使用递归实现任意数n的阶乘 普通实现
# 5! =5 *4*3*2*1n = 5total = 1for i in range(n,0,-1):total *= iprint(total) # 120递归实现
def jiecheng(n):if n <= 1:return 1return jiecheng(n-1) * nprint(jiecheng(2))# jiecheng(1) => 1 # jiecheng(2) => jiecheng(1) * 2 => 1 * 2# jiecheng(3) => jiecheng(2) * 3 => 1 * 2 * 3# jiecheng(4) => jiecheng(3) * 4 => 1 * 2 * 3 * 4# jiecheng(5) => jiecheng(4) * 5 => 1 * 2 * 3 * 4 * 5print(jiecheng(5))"""代码解析:去的过程:n = 5 return jiecheng(n-1) * n => jiecheng(4) * 5n = 4 return jiecheng(n-1) * n => jiecheng(3) * 4n = 3 return jiecheng(n-1) * n => jiecheng(2) * 3n = 2 return jiecheng(n-1) * n => jiecheng(1) * 2n = 1 return 1回的过程:n = 2 return jiecheng(1) * 2 => 1 * 2n = 3 return jiecheng(2) * 3 => 1 * 2 * 3n = 4 return jiecheng(3) * 4 => 1 * 2 * 3 * 4n = 5 return jiecheng(4) * 5 => 1 * 2 * 3 * 4 * 5到此程序结束:返回1 * 2 * 3 * 4 * 5"""2. 使用尾递归来实现任意数的阶乘return 在哪调用,在哪返回
自己调用自己,且返回时非运算表达式,只是函数本身
特点:
尾递归只开辟一个空间,不会无限的开辟,在一个空间里面去计算最后的结果进行返回,比较节省空间,有的解释器支持尾递归的调用特点
但是cpython解释器目前不支持
写法:
所有运算的值都在函数的参数中计算完毕,最后返回运算的参数;
def jiecheng(n,endval):if n <= 1:return endvalreturn jiecheng(n-1 , n * endval)res = jiecheng(5,1) # 5*4*3*2*1print(res)"""代码解析:去的过程n = 5 ,endval = 1 return jiecheng(n-1 , n * endval) => jiecheng(4,5*1) => 5*1*4*3*2n = 4 ,endval = 5*1 return jiecheng(n-1 , n * endval) => jiecheng(3,5*1*4) => 5*1*4*3*2 n = 3 ,endval = 5*1*4 return jiecheng(n-1 , n * endval) => jiecheng(2,5*1*4*3) => 5*1*4*3*2 n = 2 ,endval = 5*1*4*3 return jiecheng(n-1 , n * endval) => jiecheng(1,5*1*4*3*2) => 5*1*4*3*2 n = 1 ,endval = 5*1*4*3*2if n <= 1 成立return endvalendval = 5*1*4*3*2 最下层空间的返回值 是 5*4*3*2*1最上层接收到的返回值也是 5*4*3*2*1最下层和最上层返回的结果是一致的,所以对于尾递归来说,只需要考虑去的过程,无需考虑回的过程即可完成;图片解析

文章插图
优化代码1
def jiecheng(n,endval=1):if n <= 1:return endvalreturn jiecheng(n-1 , n * endval)res = jiecheng(5,100) # 5*4*3*2*1print(res,"<00000>")优化代码2 [把尾递归需要的参数值隐藏起来,避免篡改.]
def outer(n):def jiecheng(n,endval=1):if n <= 1:return endvalreturn jiecheng(n-1 , n * endval)return jiecheng(n,1)# 120print(outer(5))优化代码3(扩展)
闭包实现
def outer(n):endval = 1def jiecheng(n):nonlocal endvalif n <= 1:return endvalendval *= nreturn jiecheng(n-1)return jiechengfunc = outer(5)print(func(5),"<===111==>")3.使用递归来完成斐波那契数列1 1 2 3 5 8 13 21 34 ...
【Python 异常推送 python之推导式 生成器 生成器函数 递归函数】def feib(n):if n == 1 or n == 2:return 1# 上一个结果 + 上上个结果return feib(n-1) + feib(n-2)print(feib(5))"""# 代码解析:n = 5feib(5) => 3 + 2 => return 5feib(4)+feib(3)feib(3)+feib(2)feib(2)+feib(1) => 1 + 1 => 2feib(2)+feib(1)+feib(2) => 1 + 1 + 1 => 3"""
- 春季老年人吃什么养肝?土豆、米饭换着吃
- 三八妇女节节日祝福分享 三八妇女节节日语录
- 老人谨慎!选好你的“第三只脚”
- 校方进行了深刻的反思 青岛一大学生坠亡校方整改校规
- 脸皮厚的人长寿!有这特征的老人最长寿
- 长寿秘诀:记住这10大妙招 100%增寿
- 春季老年人心血管病高发 3条保命要诀
- 眼睛花不花要看四十八 老年人怎样延缓老花眼
- 香槟然能防治老年痴呆症? 一天三杯它人到90不痴呆
- 老人手抖的原因 为什么老人手会抖
