Python闭包和装饰器

知识铺垫

局部变量

1、在函数内部定义的变量称之为局部变量,在函数调用完成后,局部变量就释放掉了,因为无法在函数外部对局部变量进行调用操作,如果调用,会抛出NameError的错误

2、函数嵌套:在函数的内部又定义了一个函数,比如如下代码

# 函数嵌套
def funA():
    x = 10
    def funB():
        print(x)
    funB()
    
funA()

上图运行结果:10

通过调用funA函数,funA函数里面又调用了内嵌的funB函数

如何不通过funA()函数来调用funB()函数呢?可以在funA函数里面将funB函数进行返回,返回函数时不用加括号(函数只有在定义和调用的时候才会用到小括号)

# 函数嵌套,返回一个函数
def funA():
    x = 10
    def funB():
        print(x)
    return funB
# 方式一,通过funA()()方式进行调用
funA()()
# 方式二,将funA()赋值给一个变量,再通过该变量调用funB函数,间接的调用到了funB
# 函数内部的变量理论上在函数调用完,变量就无效了,但是现在又可以通过间接的方式调用funB
myfun = funA()
print(myfun)
myfun()

上图运行结果:

可以看到上面运行结果为:得到的是funB函数的引用

闭包

也有称之为工厂函数,就是来料加工,批量生产

# 定义一个外部函数power,然后定义内部函数,内部函数返回一个数的幂次方,外部函数返回内部函数
def power(exp):
    def exp_in(value):
        return value ** exp
    return exp_in

a = power(3)
print(a(2))   # 值为8,因为a函数是计算传入参数的3次方,这样就实现了一个计算3次方的函数,即工厂函数
b = power(4)
print(b(2))   # 置为16,因为b函数是计算传入参数的4次方,这样就实现了一个计算4次方的函数,即工厂函数

power就是工厂,由于参数不同,得到了两条产品线

装饰器

闭包的原理就是函数把函数名进行返回,那么函数能把函数名作为参数传给另外的函数吗?当然可以

演化版本一

# 演化版本一
def funa():
    print("我是funa函数。。。")

def dec(func):
    print("开始调用函数")
    funa()
    print("结束调用函数")

# 此时我想调用funa函数,但我不直接调用,我通过调用dec函数间接调用
dec(funa)

运行结果:

上面这种方式,调用funa函数,都要显式的去调用dec函数,还有更好的方式吗?有,那就是在调用funa函数的时候,它能够自觉的执行去执行dec函数,那就是使用装饰器

演化版本二:

# 演化版本二,将dec函数改为嵌套函数,并且返回值为函数引用
def dec(func):
    def call_fun():
        print("开始调用函数")
        func()
        print("结束调用函数")
    return call_fun

# 通过装饰器的语法糖,对funa函数进行装饰
@dec
def funa():
    print("我是funa函数。。。")

# 现在就可以直接调用funa函数,然后自动运行装饰器函数的代码了
funa()

运行结果与第一个版本完全一致

所以,装饰器的本质就是闭包+将函数作为参数传进去

上面装饰器的运行本质为可以拆解为

# 演化版本三(装饰器的实质调用过程),将dec函数改为嵌套函数,并且返回值为函数引用
def dec(func):
    def call_fun():
        print("开始调用函数")
        func()
        print("结束调用函数")
    return call_fun

# 这次我们不使用python语法糖
def funa():
    print("我是funa函数。。。")

# 装饰器实际的运行原理为下面
funa = dec(funa) # 将funa函数进行变换,套了一层外套函数
funa() # 再调用时就会自动执行dec函数了

多个装饰器能否用在一个函数上面呢?实际上是可以的

装饰器的调用的顺序:先里层,再外层

如何给装饰器传递参数?

在装饰器里面进行嵌套的方式,参考下图

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值