Python3之从递归到闭包再到装饰器

递归

递归指的是函数直接或间接的调用自身。
有一则故事:
从前有座山,山里有座庙,庙里有个老和尚,老和尚在给小和尚讲故事,故事的内容是:从前有座山,山里有座庙。。。。

可能图片更直观,相信都见过类似的图片吧
这里写图片描述

说明:

  • 递归一定要控制递归的次数,当符合某一条件时要终止递归调用
  • 几乎所有的递归都能用while循环来代替

递归的优缺点:
优点:可以把问题简单化,让思路更加清晰,代码更简洁
缺点:递归因系统环境影响大,当递归深度太大时,可能会得到不可预知的结果

递归调用分为两个阶段:
递推阶段:从原问题出发,按递归公式递推,从未知到已知,最终达到递归终止条件
回归条件:按递归终止条件求出结果,逆向逐步带入递归公式,回归到原问题求解

先举个递归的栗子吧,我就喜欢举例子,文字描述总不如栗子更容易理解,也正好了解一下在什么请况下使用递归比较好吧

如老和尚讲故事:

def f():
    print('从前有座山,山里有座庙,庙里有个老和尚讲故事,讲的是:')
    f()
f()

结果呢:
这里写图片描述

这个就是没有加限制此数,最后崩溃掉了

再如,用递归求阶乘:

def myfac(n):
    if n == 1:   # 限制条件,当为 1 时终止递归
        return 1
    return n * myfac(n - 1)

print(myfac(5))  # 5 的阶乘 120

递推过程:
5! = 5 * 4!
5! = 5 * 4 * 3!
5! = 5 * 4 * 3 * 2!
5! = 5 * 4 * 3 * 2 * 1!
5! = 5 * 4 * 3 * 2 * 1
回归过程:
5! = 5 * 4 * 3 * 2
5! = 5 * 4 * 6
5! = 5 * 24
5! = 120

配个图:
这里写图片描述

闭包

什么是闭包:

如果一个内嵌函数访问了外部嵌套函数的变量,则这个内嵌函数就是闭包

闭包必须满足三个条件:
  1. 必须是一个内嵌函数
  2. 内嵌函数必须引用外部函数的变量
  3. 外部函数返回值必须是内嵌函数

举个栗子:
这里写图片描述

分析以上代码:
pow2接收的返回值是什么? —–> fn , 没错,就是fn,因为maker_power内部的 fn 是一个函数,但此时没被调用,所以return 的 fn 就是一个函数名。强调:此函数虽然没被调用,但是 y 是不会被释放的。
此时的pow2实际上就是 fn 了
pow2(5) 在这时其实就是调用fn 函数了,并把 5 传进去,即x = 5,上边说的 有 y 还没有被释放,返回x 的 y 次方,即返回5^2=25

注意:fn 是函数名 fn()才是调用 fn 函数(即,函数名加括号才是调用)

再来个温习一下:
这里写图片描述

装饰器

装饰器是一个函数,传入的是一个函数,返回的也是一个函数

例如:

def 装饰器函数名(参数):
    语句块
    return 函数对象

@装饰器函数名
def 函数名(形参列表):
    语句块

装饰器的原理:
被装饰函数的变量(函数名)绑定装饰器函数调用后返回的函数

举几个例子:

def mydeco(fn):
    def fx():
        print('fx正在被调用')
    return fx

def myfun():
    print('myfun正在被调用')

myfun = mydeco(myfun)
myfun()  # 结果:fx正在被调用    为什么不是myfun正在被调用?

先理解这个例子,
mydeco(myfun) 这句是调用mydeco函数,参数是一个函数myfun,即fn = myfun,返回fx,即接收的myfun=fx,
myfun()就是调用fx(),执行print(‘fx正在被调用’)这句话,所以打印的不是myfun正在被调用,跟他根本没有关系。

另一个写法:

def mydeco(fn):
    def fx():
        print('fx正在被调用')
    return fx

@mydeco
def myfun():
    print('myfun正在被调用')

# myfun = mydeco(myfun)
myfun() 

再深入一层讲解装饰器:
先看代码:

def mydeco(fn):
    def fx():
        print('这是被装饰之前')
        fn()  # 调用被装饰函数
        print('这是被装饰之后')
    return fx

@mydeco
def myfun():
    print('myfun正在被调用')

myfun()

myfun() 再次讲解这句话,加深理解上边的栗子
myfun实际可以写成两句话:
myfun = mydeco(myfun)
myfun()
初步可认为是调用myfun函数,但是myfun有装饰器,所以myfun会当做一个参数传入装饰器函数里,即fn = myfun,调用mydeco函数,先执行print(‘这是被装饰之前’)这就话,然后执行fn()函数,即调用myfun()函数,执行print(‘myfun正在被调用’)这句话,fn()函数执行完毕,继续执行装饰器函数,执行print(‘这是被装饰之后’)这句话,
所以最后打印结果是:

这是被装饰之前
myfun正在被调用
这是被装饰之后

装饰器应用:

def privieged_check(fn):
    def fx(name, x):
        print('正在进行验证...')
        if True:
            fn(name, x)
        else:
            print('权限验证失败')
    return fx

def message_send(fn):
    def fy(name, money):
        fn(name, money)
        print('正在发送短息给', name)
    return fy

@message_send
@privieged_check
def savemoney(name, x):
    print(name, '存钱', x, '元')

savemoney('小张', 200)

注意:如果被装饰的函数有多个装饰器,优先执行最近的
执行结果:

正在进行验证...
小张 存钱 200 元
正在发送短息给 小张

执行过程:
这里写图片描述

其实自己绕绕也就绕出来了!

愿意和大家一起交流,huamuxiong_2018@163.com
本节图有网上百度的,有助于理解,如果有侵权,还请告知,我会删除,谢谢

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

秒不可闫M先生

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

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

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

打赏作者

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

抵扣说明:

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

余额充值