装饰器和递归
装饰器
软件开发中有⼀条⾮常重要的规则就是:对修改封闭,对扩展开放。对于⼀个现有的函数,如果想要增强此函数的功能,但是不允许修改此函数源代码的时候,使⽤装饰器来解决这个问题
本质:就是⼀个闭包,还是⼀个返回函数的⾼阶函数
好处:就是在不⽤修改原函数代码的前提下给函数增加新的功能
装饰器是一种设计模式,即套路
基本写法
def demo(name): # 1.原函数,需要增加功能
print(f"{name},加油!")
def wrapper(func): # 2. 装饰器,将原函数包装起来
def inner(name): # 3.内部函数,运行原函数,增加 新功能
func(name) # 4.原函数
print("岂曰无衣,与子同袍!") # 5.增加的新功能
retrun inner
调用
demo = wrapper(demo) # 1.运行wrapper,结果是返回inner函数名
demo("武汉") # 2.执行inner("武汉"),既运行了原函数,又运行了新功能
使⽤@语法糖将装饰器应⽤到指定函数上,简化使⽤(写法一样,调用时后先用@再定义原函数,调用时直接使用原函数)
def wrapper(func): # 2. 装饰器,将原函数包装起来
def inner(name): # 3.内部函数,运行原函数,增加 新功能
func(name) # 4.原函数
print("岂曰无衣,与子同袍!") # 5.增加的新功能
retrun inner
@wrapper # 相当于 demo = wrapper(demo) 1.运行wrapper,结果是返回inner函数名
def demo(name): # 1.原函数,需要增加功能
print(f"{name},加油!")
demo("武汉") # 2.执行inner("武汉"),既运行了原函数,又运行了新功能
带有不定⻓参数的装饰器
同⼀个装饰器可以应⽤于多个函数
def wrapper(func):
def inner(*args,**kwargs): # 不定长参数
func(*args,**kwargs)
print("-"*50)
return inner
@wrapper
def printLine(a,b): # 1.装饰器应用于本函数(两个参数)
print(a,b)
printLine(5,7)
@wrapper
def printLine(*args,**kwargs): # 2.装饰器应用于本函数(不定长参数)
print(args,kwargs)
printLine(5,a=3,b=4)
多个装饰器作⽤在⼀个函数上
def wrapper1(func):
print("wrapper1~~~~外部函数")
def inner1(a, b):
print('wrapper1-----内部函数')
func(a, b)
return inner1
def wrapper2(func):
print("wrapper2~~~~外部函数")
def inner2(a, b):
print("wrapper2~~~~内部函数")
func(a, b)
return inner2
@wrapper1
@wrapper2 # text = wrapper1(wrapper2(text))
def text(num1, num2):
print(num1 + num2)
text(10, 20)
装饰器先后顺序有关系:
@wrapper1
@wrapper2
相当于 text = wrapper1(wrapper2(text))
@wrapper2
@wrapper1
相当于text = wrapper2(wrapper1(text))
以wrapper1(wrapper2(text))为例运行顺序:
(1)wrapper2(text),此时func=text打印输出"wrapper2~外部函数",定义并返回函数inner2
(2)wrapper1(inner2),此时func=inner2,输出"wrapper2~外部函数",定义并返回函数inner1
(3)text(10,20),相当于执行inner1(10,20),输出’wrapper1-----内部函数’,执行func(10,20),此时func=inner2,即执行inner2(10,20):打印"wrapper2~~~~内部函数",再执行func(a,b),此时func=text,即执行text(10,20),返回30,结束函数。
递归函数
== 递归的不可替代性 == 刘江的博客教程
- 嵌套调⽤
在函数A中可以调⽤函数B,在函数B中可以调⽤函数C,这种调⽤⽅式称为函数的嵌套调⽤。
嵌套调用:函数执行时遇到调用另一个函数,则会先停止本函数,等待另另一个函数执行完毕再继续执行。如下例,demoC()执行时调用demoB(),则停止执行demoC(),先执行demoB(),执行demoB()时又调用了demoA,则先执行demoA结束,再执行deomB剩余语句,再执行demoC剩下语句。
# 递归
def demoA():
print("A")
print("------")
def demoB():
print("B")
demoA()
print("*****")
def demoC():
print("C")
demoB()
print("=====")
# 函数嵌套调用的原理
demoC()
- 递归调⽤与写法:⼀个函数直接或间接的调⽤⾃⼰则称为递归调⽤。
⼀个递归程序必须包含两部分:
1)递归终⽌条件
2)递归调⽤⾃⼰
def recurve(*args,**kw):
if 递归终⽌条件: #递归终⽌条件必须在递归调⽤前
# to do
else:
#to do
recurve(参数)
def fac(n):
if n == 0: # 1. 要先确定递归终止条件
return 1
tmp=fac(n-1)
return tmp*n # 2. 递归调用
print(fac(100))
递归调⽤可分解为两个过程,正向递归调⽤和逆向递归返回。
- 递归适⽤条件
如果⼀个问题规模缩减后,求解⽅式和原来⼀样,⼩规模问题
解决后导致问题的最终解决,则可适⽤递归
理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。
- 形式是递归的如阶乘和斐波那契数列
- 结构是递归的如列表遍历
- 解法是递归的如汉诺塔
作业
主程序:
while True:
print('''******欢迎使⽤成绩管理系统********
[1] 学⽣信息输⼊
[2] 学⽣信息输出
[3] 查找学⽣信息
[4] 成绩排序
[0] 退出
********************************''')
subMenu = input("请输入你的选择【0-4】:")
if subMenu == '0':
break
elif subMenu == '1':
score_def.infoInput()
elif subMenu == '2':
score_def.infoOutput()
elif subMenu == '3':
score_def.infoSearch()
elif subMenu == '4':
score_def.infoOrder()
else:
print("请输入0、1、2、3、4中的一个。")
模块:
infoList = []
def mainMenu():
print('''
******欢迎使⽤成绩管理系统********"
[1] 学⽣信息输⼊
[2] 学⽣信息输出
[3] 查找学⽣信息
[4] 成绩排序
[0] 退出
********************************
''')
fm = "\t{:>8}\t{:>8}\t{:>8}\t{:>8}\t{:>8}\t{:^8}"
fm1 = "{:>5}{:>8}{:>5}{:>5}{:>5}{:>5}"
def infoInput():
while True:
info = input(f"请输入第{len(infoList)+1}个学生的信息,按n退出(请按姓名、学号、数学成绩、计算机成绩输入,如张三,200901,95,100:)").split(",")
if len(infoList)>30:
print("该班人数不超过30")
break
if info[0] == 'n':
print(infoList)
break
for i in infoList:
if i["id"] == info[1]:
print("重复输入相同id号学生")
break
else:
infoList.append({"name": info[0], "id": info[1], "math": int(info[2]), "computer": int(info[3])})
def infoOutput():
print(fm.format("姓名","id","数学","计算机","总分","平均分"))
for k in infoList:
print(fm.format(k['name'],k['id'],k['math'],k['computer'],k['computer']+k['math'],(k['computer']+k['math'])/2))
def infoSearch():
id = input("输入要查找的学号:")
for k in infoList:
if k['id'] == id:
print(fm1.format(k['name'],k['id'],k['math'],k['computer'],k['computer']+k['math'],(k['computer']+k['math'])/2))
break
else:
print("无此id号")
def infoOrder():
if len(infoList) != 0:
for j in range(len(infoList)-1):
for i in range(len(infoList)-1-j):
if infoList[i]['math']+infoList[i]['computer'] < infoList[i+1]['math']+infoList[i+1]['computer']:
infoList[i], infoList[i+1] = infoList[i+1], infoList[i]
else:
print("没有任何学生记录")
print(fm.format("姓名","id","数学","计算机","总分","平均分"))
for k in infoList:
print(fm.format(k['name'],k['id'],k['math'],k['computer'],k['computer']+k['math'],(k['computer']+k['math'])/2))