python装饰器详解(Decorator)

装饰器(Decorator)

装饰器

1.如果要增强一个函数的功能,但又不希望更改原函数中的代码,这种在代码运行期间动态增加功能的机制被称为装饰器

【Decorator】

2. 本质:实际上就是一个闭包,只不过被装饰的函数需要作为参数传递给闭包

3.装饰器的书写格式:给闭包的外部函数设置一个参数【需要被装饰的函数】,外部函数的返回值是内部函数的引用【装饰的结果】,这种函数被称为高阶函数

4.装饰器的好处

① 不用修改源代码就可以更改函数

② 提高代码的维护性

③ 提高代码的复用性

5.应用场景:

① 引入日志

② 统计函数的执行时间

③权限校验

④缓存

一、案例1:股票交易(买入、卖出)

版本1:

  • 简单的买入、卖出

# encoding: utf-8
# @File  : test01.py
# @Author: wu shaofan
# @Desc : 股票买入、卖出
# @Date  :  2024/02/08
​
def buy():
    print("买入股票成功")
​
​
def sell():
    print("卖出股票成功")
​
​
if __name__ == '__main__':
    buy()
    sell()
买入股票成功
卖出股票成功
​
Process finished with exit code 0

版本2:

  • 想买入或者卖出之前,输入密码验证

  • # encoding: utf-8
    # @File  : test02.py
    # @Author: wu shaofan
    # @Desc : 卖出、买入股票需要输入密码
    # @Date  :  2024/02/08
    ​
    def buy():
        password = input("请输入密码:")
        if password == "123456":
            print("买入股票成功!")
        else:
            print("密码错误,买入股票失败!")
    ​
    def sell():
        password = input("请输入密码:")
        if password == "123456":
            print("卖出股票成功!")
        else:
            print("密码错误,卖出股票失败!")
    ​
    ​
    if __name__ == '__main__':
        buy()
        sell()

       

    请输入密码:123456
    买入股票成功!
    请输入密码:123456
    卖出股票成功!
    ​
    Process finished with exit code 0

    缺点:

    功能有了,不过buy()和sell()方法变复杂了,且每个函数中有重复的代码,如果buy()和sell()方法是别人写的,功能已经完善了,最好不要改动代码

版本3:

  • 重新定义一个方法

    # encoding: utf-8
    # @File  : test03.py
    # @Author: wu shaofan
    # @Desc : 
    # @Date  :  2024/02/08
    ​
    def buy():
        print("买入股票成功")
    ​
    ​
    def sell():
        print("卖出股票成功")
    ​
    ​
    def pwd(order):
        password = input("请输入密码:")
        if password == "123456":
            order()
        else:
            print("密码错误,请重新输入!")
    ​
    ​
    if __name__ == '__main__':
        pwd(buy)
        pwd(sell)
    请输入密码:123456
    买入股票成功
    请输入密码:123456
    卖出股票成功
    ​
    Process finished with exit code 0

    期望:买入、卖出还是就执行buy和sell方法

版本4:装饰器一般写法

# encoding: utf-8
# @File  : test04.py
# @Author: wu shaofan
# @Desc : 
# @Date  :  2024/02/08
​
def buy():
    print("买入股票成功")
​
​
def sell():
    print("卖出股票成功")
​
​
def pwd(order):
    def order_new():
        password = input("请输入密码:")
        if password == "123456":
            order()
        else:
            print("密码错误,请重新输入!")
    return  order_new
​
if __name__ == '__main__':
    buy = pwd(buy)
    buy()
请输入密码:123456
买入股票成功
​
Process finished with exit code 0

版本5:标准的语法糖写法

功能已经实现,不过python提供了更好的方法

python做了一个优化;提出了一个语法糖的概念。 标准版的装饰器

( @pwd 等于buy = pwd(buy) )

# encoding: utf-8
# @File  : test04.py
# @Author: wu shaofan
# @Desc : 
# @Date  :  2024/02/08
​
def pwd(order):
    def order_new():
        password = input("请输入密码:")
        if password == "123456":
            order()
        else:
            print("密码错误,请重新输入!")
    return  order_new


#TODO ​@pwd 等价于 buy = pwd(buy)
@pwd
def buy():
    print("买入股票成功")
​
@pwd
def sell():
    print("卖出股票成功")
    
buy()    
请输入密码:123456
买入股票成功
​
Process finished with exit code 0

版本6:被装饰函数有返回值

# encoding: utf-8
# @File  : test04.py
# @Author: wu shaofan
# @Desc : 被装饰函数有返回值
# @Date  :  2024/02/08

def pwd(order):
    def order_new():
        password = input("请输入密码:")
        r = None   # 初始化 r 为 None,不初始化也没问题,不过根据python语法规则会有警告
        if password == "123456":
            r = order()
        else:
            print("密码错误,请重新输入!")
        return r
    return  order_new

@pwd
def buy():
    print("买入股票成功")
    return "买入666"

@pwd
def sell():
    print("卖出股票成功")
    return "卖出666"


obj =  buy()
print(obj)

请输入密码:123456
买入股票成功
买入666

Process finished with exit code 0

版本7:被装饰函数带参数

# encoding: utf-8
# @File  : test04_1.py
# @Author: wu shaofan
# @Date  :  2024/02/09
# @Desc : 被装饰函数带参数


def pwd(order):
    def order_new(*args,**kwargs):
        password = input("请输入密码:")
        r = None   # 初始化 r 为 None,不初始化也没问题,不过根据python语法规则会有警告
        if password == "123456":
            r = order(*args,**kwargs)
        else:
            print("密码错误,请重新输入!")
        return r
    return  order_new

@pwd
def buy(name):
    print("{}买入股票成功".format(name))
    return "买入666"

@pwd
def sell(age,name):
    print("{}岁的{}卖出股票成功".format(age,name))
    return "卖出666"

obj =  buy("吴彦祖")
print(obj)

obj = sell(18,"吴彦祖")
print(obj)
请输入密码:123456
吴彦祖买入股票成功
买入666
请输入密码:123456
18岁的吴彦祖卖出股票成功
卖出666

Process finished with exit code 0

版本8:被装饰器函数带参数进阶版

装饰器也带参数

# encoding: utf-8
# @File  : test04_02.py
# @Author: wu shaofan
# @Date  :  2024/02/09
# @Desc : 被装饰器带参数进阶版
def pwd(type):
    def order_new(order):
        def infunc(*args,**kwargs):
            password = input("请输入密码:")
            r = None   # 初始化 r 为 None,不初始化也没问题,不过根据python语法规则会有警告
            if password == "123456" and type == "买入":
                r = order(*args,**kwargs)
            elif password == "123456" and type == "卖出":
                r = order(*args,**kwargs)
            else:
                print("密码错误,请重新输入!")
            return r
        return infunc
    return  order_new

@pwd("买入")
def buy(name):
    print("{}买入股票成功".format(name))
    return "买入666"

@pwd("卖出")
def sell(age,name):
    print("{}岁的{}卖出股票成功".format(age,name))
    return "卖出666"

obj =  buy("吴彦祖")
print(obj)

obj = sell(18,"吴彦祖")
print(obj)
请输入密码:123456
吴彦祖买入股票成功
买入666
请输入密码:123456
18岁的吴彦祖卖出股票成功
卖出666

Process finished with exit code 0

总结:标准版的装饰器

标准版的装饰器;

def wrapper(f):
    def inner(*args,**kwargs):  #  函数的定义:* 聚合  args = ('李舒淇',18)
        '''添加额外的功能:执行被装饰函数之前的操作'''
        ret = f(*args,**kwargs) #* 打散:f(*args) --> f(*('李舒淇',18))  --> f('李舒淇',18)
        ''''添加额外的功能:执行被装饰函数之后的操作'''
        return ret
    return inner

二、装饰器进阶

1、类装饰器

        类装饰器这个写法,主要思路就是返回一个增加了新功能的函数对象,只不过这个函数对象是一个类的实例对象。由于装饰器是可调用对象,所以必须在类里面实现call方法,这样由类生成的各种实例加上()就可以运行了。

1.1、不带参数的类装饰器

# encoding: utf-8
# @File  : test11.py
# @Author: wu shaofan
# @Date  :  2024/02/10
# @Desc : 不带参数的类装饰器

class Decorator:
    def __init__(self, func):
        self.func = func

    def start(self):
        print("此方法在函数运行之前被调用")

    def end(self):
        print("此方法在函数运行结束之后被调用")


    def __call__(self, *args, **kwargs):
        self.start()
        self.func()
        self.end()


# f1 =  Decorator(f1)
@Decorator
def f1():
    print("我是被装饰函数")

f1()

##########################################
此方法在函数运行之前被调用
我是被装饰函数
此方法在函数运行结束之后被调用

Process finished with exit code 0
过程分析:

 拓展:call()方法介绍

2,带参数的类装饰器

 

import time
 
class Decorator:
    def __init__(self, func):
        self.func = func
 
    def defer_time(self,time_sec):
        time.sleep(time_sec)
        print(f"{time_sec}s延时结束了")
 
    def __call__(self, time):
        self.defer_time(time)
        self.func()
 
@Decorator
def f1():
    print("延时之后我才开始执行")
 
f1(5)

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值