Python基础之装饰器

装饰器的引入

  • 我们可以直接通过修改函数中的代码来完成需求,但会产生以下一些问题。
    • 如果修改的函数多,修改起来会比较麻烦。
    • 不方便后期的维护。
    • 这样做会违反OCP原则(ocp:开闭原则,程序的设计,要求开发对程序的扩展,要关闭对程序的修改)
  • 装饰器的作用:
    • 通过装饰器,可以在不修改原来函数的情况下对函数进行扩展。
    • 在开发中,我们都是通过装饰器来扩展函数功能的。

一、普通装饰器的创建

先决条件:因为装饰器本质上是一个闭包,所以它也符合闭包的三个特性:

  • 函数嵌套
  • 内部函数需要用到外部函数的变量或者参数
  • 外部函数返回内部函数的函数对象
def   fun_out(fn):
    print("我是外部函数")
    def  fun_inner():
        print("我是内部函数")
        fn()
        
    return fun_inner

以上就是这个高级函数就是一个闭包了,既然有装饰器的使用,那么当然也需要一个被装饰的目标函数了,接下来创建一个被装饰的目标函数,如下:

def fun():
   print("我是装饰的第一个目标函数")

现在准备工具已经完成,我们来调用程序看看这个结果。

def   fun_out(fn):
    print("我是外部函数")
    def  fun_inner():
        print("我是外部函数")
        fn()

    return fun_inner

def fun():
    print("我是装饰的第一个目标函数")

f = fun_out(fun)
f()
#执行结果如下
我是外部函数
我是外部函数
我是装饰的第一个目标函数

那么这就是我们的执行结果了,可以看到我们完成了程序的添加,但是并没有对程序本身功能做更改。但是这么写不是太友好,如果说使用人员使用这个程序,步骤的增多会降低体验度,同时,这样也会把开发人员的目光吸引到如何调用装饰器上,而不是针对目标函数做装饰,所以我们一般是使用语法糖的写法。

def   fun_out(fn):
    print("我是外部函数")
    def  fun_inner():
        print("我是外部函数")
        fn()

    return fun_inner
@fun_out
def fun():
    print("我是装饰的第一个目标函数")

#f = fun_out(fun)
fun()     
输出结果如下:
我是外部函数
我是外部函数
我是装饰的第一个目标函数

这样的使用显然更加的便捷。

通用装饰器的创建

含义:装饰的函数是否携带参数都可以保证程序的正常运行,则称之为通用装饰器。

在上面的例子中我们可以发现,如果在调用的时候时候给他传递参数的时候会怎样呢,答案肯定是会报错的,又或者说在创建装饰器的时候,需要传递参数但调用的时候没有传递参数的话也会报错,这样就显得很不方便。所以我们给内部函数添加不定长参数,不管目标函数是否携带参数都能够使用此装饰器。

def   fun_out(fn):
    print("我是外部函数")
    def  fun_inner(*args,**kwargs):
        print("我是外部函数")
        fn(*args,**kwargs)

    return fun_inner
@fun_out
def fun(a,b):
    print("我是装饰的第一个目标函数")
    print(a + b )
#f = fun_out(fun)
fun(10,100)
输出结果如下:
我是外部函数
我是外部函数
我是装饰的第一个目标函数
110

三、携带参数的装饰器的使用

携带参数的装饰器是一个比较特殊的装饰器了,当我们使用的装饰器是携带了参数的时候,我们必须在装饰器的外层在包裹一层函数才可以。


def  loggin(sign):
    def  fun_out(fun):
        def fun_inner(num1,num2):
            if  sign == "*":
                print("正在调用乘法运算")
            elif sign == "/":
                print("正在调用除法运算")
            result = fun(num1,num2)
            return result
        return fun_inner
    return fun_out

@loggin("/")
def func(a,b):
    res = a / b
    return res

@loggin("*")
def func2(a,b):
    res2 = a * b
    return res2
res = func(8,2)
print(res)
res2 = func2(8,2)
print(res2)
#输出结果:
正在调用除法运算
4.0
正在调用乘法运算
16

四、多个装饰器的使用

我们都知道使用一个装饰器,我们的目标函数没有问题,哪如果我们使用多个装饰器会是怎样的呢?

import time
def fun_out(fun):
    def fun_inner(*args, **kwargs):
        begin = time.time()
        res = fun(*args, **kwargs)
        end = time.time()
        print('程序执行时间为%s' % (end - begin))
        return res
    return fun_inner
def login(fun):
    def wrapper(*args, **kwargs):
        print('请先登录')
        res = fun(*args, **kwargs)
        return res
    return wrapper
@fun_out
@login
def fun1(a, b):
    time.sleep(1)
    return a + b
r = fun1(1, 2)
print(r)
运行结果如下:
请先登录
程序执行时间为1.0003249645233154
3

那么大家有没有注意到程序的执行顺序问题,装饰器的执行顺序是从下往上执行的,并不是我们想象中的从上往下执行,这个是多个装饰器同时装饰一个目标函数的特殊性质,哪个装饰器离目标函数近,那么那个装饰器就先执行。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值