python_装饰器

装饰器是python基础语法中比较晦涩难懂的地方,借此机会,谈谈自己对装饰器的理解。

一、什么是装饰器

装饰:给别的函数添加功能

器:就是具有某种作用的工具

装饰器:给其他函数添加功能的工具,本质也是函数,而且是一个闭包函数。

二、为什么要有装饰器

一、函数传参的另外一种形式

之前我们学的函数传参都是类似于如下:

def func(a,b):
    print(a,b)

有了装饰器之后我们可以这样传参:
这里是为deco传的参数,这里的deco就是一个装饰器,他需要一个参数是func,即被装饰函数的地址

def wrapper(func):
    def deco(*args,**kwargs):
        print('in the wrapper')
        res = func(*args,**kwargs)
        return res
     return deco

def func2():
    print(123)

那为什么不这样写?

 def deco(func,*args,**kwargs):
        print('in the wrapper')
        res = func(*args,**kwargs)
        return res

我将在下面解释

二、在不改变函数源代码和调用方式的情况下为函数添加功能,具体用法在下面介绍

三、怎么用装饰器

def wrapper(func):
    def deco(*args,**kwargs):
        print('in the wrapper')
        res = func(*args,**kwargs)
        return res
     return deco

def func2():
    print(123)

前面已经说过,deco就是一个装饰器,本质是闭包函数。对于闭包函数简单一提,在python中万物皆对象,因此函数也可以作为其他函数的参数、返回值、也可以作为容器类型的元素

x = 4
def deco():
	x = 1
    def func():
        print(x)

闭:可以理解为一个麻袋把函数套起来,这里的麻袋就是deco

包:可以理解为麻袋里面的东西,这里的x就是麻袋里的东西,这里打印的x是1

闭包函数的名字的查找关系是以函数定义阶段为准,可以理解为局部变量覆盖了全局变量

四、语法糖

形式:@函数名

def wrapper(func):
    def deco(*args,**kwargs):
        print('in the wrapper')
        res = func(*args,**kwargs)
        return res
     return deco
@wrapper
def func2():
    print(123)

这里func2被deco装饰,@wrapper等价于func2 = wrapper(func2),为func2多加了一个功能,即打印了in the wrapper,那为什么不能在定义deco的时候多一个函数参数呢,那是因为实际上func2变成了 deco,真正调用func2的时候会是这样

func2()

func2被装饰后,运行的就是deco了,但是用户丝毫不清楚这个过程,因为调用方式没变,函数(指的是func2)的代码也没变,如果加上一个函数参数,那么在调用的时候会出错,说是少了一个参数。这里的deco参数和func2的函数应该保持一致。

有参装饰器,简单一提(其实可以不用语法糖实现,省略,因为比较low)

def outter(x):
    def wrapper(func):
        print(x)
        def deco(*args,**kwargs):
            print('in the wrapper')
            res = func(*args,**kwargs)
            return res
        return deco
    return wrapper
@outter(1)
def func2():
    print(123)
func2()

多层装饰器的加载顺序是从下往上,运行顺序是从上往下。

def deco1(func1): # func1 = wrapper2的内存地址
    def wrapper1(*args,**kwargs):
        print('正在运行===>deco1.wrapper1')
        res1=func1(*args,**kwargs)
        return res1
    return wrapper1

def deco2(func2): # func2 = wrapper3的内存地址
    def wrapper2(*args,**kwargs):
        print('正在运行===>deco2.wrapper2')
        res2=func2(*args,**kwargs)
        return res2
    return wrapper2

def deco3(x):
    def outter3(func3): # func3=被装饰对象index函数的内存地址
        def wrapper3(*args,**kwargs):
            print('正在运行===>deco3.outter3.wrapper3')
            res3=func3(*args,**kwargs)
            return res3
        return wrapper3
    return outter3


# 加载顺序自下而上(了解)
@deco1      # index=deco1(wrapper2的内存地址)        ===> index=wrapper1的内存地址
@deco2      # index=deco2(wrapper3的内存地址)        ===> index=wrapper2的内存地址
@deco3(111) # ===>@outter3===> index=outter3(index) ===> index=wrapper3的内存地址
def index(x,y):
    print('from index %s:%s' %(x,y))

# 执行顺序自上而下的,即wraper1-》wrapper2-》wrapper3
index(1,2) # wrapper1(1,2)

更加伪装:

from functools import wraps

def outter(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        """这个是主页功能"""
        res = func(*args, **kwargs) # res=index(1,2)
        return res


    # 手动将原函数的属性赋值给wrapper函数
    # 1、函数wrapper.__name__ = 原函数.__name__
    # 2、函数wrapper.__doc__ = 原函数.__doc__
    # wrapper.__name__ = func.__name__
    # wrapper.__doc__ = func.__doc__

    return wrapper

讲解链接:

python

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

aJupyter

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

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

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

打赏作者

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

抵扣说明:

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

余额充值