python装饰器是如何实现的?-----闭包

讲闭包之前,我们需要模拟一个简单的场景,用不同的形式实现。
场景:准备好人民币,去银行换美元 或者 日元。
1. 用函数实现

rate_usa = 0.7  # 美元汇率
rate_jp = 100   # 日元汇率  

def ret_money(rate, money):
    print(rate * money)   # 汇率 * 钱数 就是我们可以换得了多少

ret_money(rate_usa, 1000)   # 1000元 换 美元 
ret_money(rate_usa, 2000)   # 2000元 换 美元 
ret_money(rate_jp, 100)   # 100元 换 日元 
ret_money(rate_jp, 200)   # 200元 换 日元

这是我想到的最简单的方法来实现,那么发现一个问题,每次我要计算的时候,都需要去传汇率和要换的钱数,如果要计算100次、1000次,那一定疯掉,所以我需要其他更简单的方法实现。。。。
2. 面向对象实现:

rate_usa = 0.7
rate_jp = 100


class RetMoney(object):
    def __init__(self, rate):  # rate=汇率
        self.rate = rate

    def result(self, money):  # money=要换的钱数
        print(self.rate * money)  


ret_money = RetMoney(rate_usa)  # 创建实例 传入汇率
ret_money.result(1000)   # 调用计算方法,传入要换的钱数
ret_money.result(2000)
ret_money2 = RetMoney(rate_jp)
ret_money.result(100)
ret_money.result(100)

面向对象方法实现,很明显,汇率我只穿一次,之后我只改要换的钱数,方便了很多,但是似乎还是有些浪费资源,是不是还有更好的方法呢?闭包要登场了。。。。
3. 闭包实现:

rate_usa = 0.7
rate_jp = 100

def ret_money(rate):
    def result(money):
        print(rate * money)

    return result


result_usa = ret_money(rate_usa)
result_jp = ret_money(rate_jp)

result_usa(1000)
result_usa(2000)
result_jp(100)
result_jp(200)

那么这种形式,就是闭包

闭包的格式:
        函数嵌套,
        内部的函数需要用到外部的变量,
        外部函数返回内部函数的引用,
        外部函数必须有一个参数

尽管列出了闭包的格式,初次见到闭包的人也一定会很懵
先看一段代码:

def a():
    print("11111")

a()

很显然 输入“11111”
那么改一下

def a():
    print("11111")

print(a)

输出了一个对象,<function a at 0x103860e18> ,似乎告诉这个函数位于一个地址
其实当程序执行时,看到def 发现是要定义一个函数,那么就会创建一个变量 a 再将函数体放在一个内存地址,并让a指向这个地址—-如下图:
这里写图片描述

那么闭包其实就是一种特殊的函数利用函数引用来实现
创建一个新的变量,让它指向闭包中,内部函数的引用,
给这个新变量加上一对括号,就相当于执行了闭包中的内部函数。

你可能会想为什么这么麻烦来解决,直接用一个函数,定义几个全局变量不就可以解决吗?话粗理不粗,确实有几分道理,那接下来用闭包来实现另外一个场景。。。。

场景:我有一个已经写好的函数,实现了转账的功能,突然你的领导说让你在不改变写好的函数代码结构及结果的情况下,添加一个身份验证的功能,该如何修改?闭包就派上用场了,下面我们来实现一下

伪代码: 在不修改这个函数的结构及结果的情况,添加额外的身份验证功能
def test():
    print("转账功能...")
# 闭包实现 添加身份验证功能
def set_fun(func):
    def call_fun():
        print("身份验证")
        return func()

    return call_fun

# 转账功能
def test():
    print("转账功能")


test = set_fun(test)

test()

初次接触闭包的人,看上一个场景实现的闭包可能还能看得懂,这个可能会有些懵,可以看下面的图片,具体的分析的这段代码的执行过程(由于软件没办法写那么多,分成了两张图):

这里写图片描述

这里写图片描述

上面的图片比较详细的分析了整个过程,
那么这种利用闭包的特性,在不改动原有代码的情况,为一个函数添加额外的功能,叫做装饰器。那么真正的装饰器有特定的写法。

def set_fun(func):
    def call_fun():
        print("身份验证")
        func()

    return call_fun


@set_fun  # 这行代码相当于 test = set_fun(test)
def test():
    print("转账功能")


# test = set_fun(test)  注释这行代码

test()

在需要添加额外功能的函数上面,写@+闭包外层函数的函数引用,这就是一个装饰器,闭包大部分都是用来完成装饰器而使用的。
@set_fun 其实是python的语法糖,告诉程序员这是一个装饰器。

装饰器是什么:@闭包的外部函数引用
装饰器作用:装饰我们的函数,给函数添加额外的功能,不改变装饰前的函数代码(道德)
代码怎么写:
#1.先写闭包
#2.在要装饰的函数上写闭外外层的引用

后续还会写一篇根据要装饰的函数的不同情况(有参无参有返回无返回—到万能)需要如何修改的文章 - 。-iiii

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值