day14-15:函数(3)-- 装饰器和递归

装饰器

软件开发中有⼀条⾮常重要的规则就是:对修改封闭,对扩展开放。对于⼀个现有的函数,如果想要增强此函数的功能,但是不允许修改此函数源代码的时候,使⽤装饰器来解决这个问题
本质:就是⼀个闭包,还是⼀个返回函数的⾼阶函数
好处:就是在不⽤修改原函数代码的前提下给函数增加新的功能
装饰器是一种设计模式,即套路

基本写法

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,结束函数。

递归函数

== 递归的不可替代性 == 刘江的博客教程

  1. 嵌套调⽤
    在函数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. 递归调⽤与写法:⼀个函数直接或间接的调⽤⾃⼰则称为递归调⽤。
    ⼀个递归程序必须包含两部分:
    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))

递归调⽤可分解为两个过程,正向递归调⽤和逆向递归返回。
在这里插入图片描述

  1. 递归适⽤条件
    如果⼀个问题规模缩减后,求解⽅式和原来⼀样,⼩规模问题
    解决后导致问题的最终解决,则可适⽤递归
    理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。
  • 形式是递归的如阶乘和斐波那契数列
  • 结构是递归的如列表遍历
  • 解法是递归的如汉诺塔

作业

主程序:

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))
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值