【实测】:python的装饰器如何传参?

130 阅读5分钟

「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」。

今天在设计一个django权限控制器的时候,陷入到了一个问题中,就是如何多角度的给一个函数的装饰器传参。问题并不难,也完美解决。所以这里要给大家用 土话 来讲一下装饰器和不同方式传参的方法。

一:先明白下什么是装饰器?

    装饰器就相当于给你当前的这个函数增加点装饰效果,外挂效果等的函数。它接收你这个函数为参数,然后装饰加工完再帮你运行。

二:函数本身也可以当做参数

    众所周知,函数后面加括号是调用,不加括号代表是本身,其实函数也是个对象。

所以看这个demo:

图片

如图,我调用x,把函数a当做参数传递给x,其中我特意用func作为一个参数变量,虽然你叫什么都可以,但是大家以后记住在任何教程中看到func就代表一个函数变量,别问为啥,这是规矩。

输出的结果是:

图片

如图可以见,x确实运行了,并且打印了函数a的名字:a ,但是函数a本身并未运行,所以内部的hello无法执行打印。

然后我们在x函数中对a函数进行稍微的加工,不加工你要装饰器干嘛?

所以按照人家规定,我们需要在x中新增了个内部函数y,y负责对a进行加工(其实就是帮忙运行一下a或者在之前之后做点别的事), 定义了y之后,在x的结尾要运行y 才有意义。此时我们再调用x,就会发现,a也被执行并打印了hello。

比如我们再打印a之后再打印别的文字,就相当于进行了简单装修加工:

图片

这样的效果,才是一个装饰器存在的意义。

此时,函数x 就是 函数a的装饰器,但是不用这么写,python叫你用@的方式来写,继续往下看!

三,装饰器写法

图片

如图,装饰器的简单写法就是上面这样了,直接在函数a脑袋上用回形针别了个函数x,这样我们真正调用的时候就无需调用x了,直接还是按照原始的调用a就可以了就是a()。但是因为我们变成了调用函数a,所以也就无需函数x的最后帮忙去调用y函数,而是直接把y函数返回就行了,我们a函数自己会调用,不用它帮忙!

大家如果还没完全理解,也是正常的,但是请死记硬背上面的这段代码哦,因为后面复杂的全是由这个升级来的。

四:装饰器传参数

实际运用中,肯定需要传递数据给装饰器,不然装饰器就瞎装修了。

传参数一共有3个路线传参:

路线一:a函数的入参给到装饰器里用

图片

如上图,func在装饰器内就相当于a函数本身,但是要通过y函数来接收所有参数才行,args和kwargs是python基础知识,代表接收所有参数,这里不多做赘述,不明白的可以报我培训班,按照路线正式学一遍。

你可以理解为,a函数送去装修团队手里装修了,你要给它递点东西,肯定要人家装修团队的人从你手接过去,然后再安装到a函数身上的意思,所以是在y函数上进行首次接收。

路线二:让装饰器自己接收参数

这个传参就比较难了,因为目前的结构并不支持,必须要再多加一层包装才行。因为目前x函数负责接收a函数本体,y函数负责接收a函数的参数。那外来的其他参数 就只能在它们最外层再包一层z,来接收了。

如图:

图片

改成了上图这样后,你想单独给装饰器传的参数money,就可以直接给了。z负责接收。

最后,为了便于大家记住这个装饰器,我教大家一个联想记忆。

大家把这个装饰器看成一个装修施工团队,你的a函数就是你的毛坯房。其中z函数是财务,负责接收你给的钱,x函数是施工方,负责接收你的房子a。y函数是打杂的,负责接收你的买的一些家电家具。

然后我们看本集最坑的第三种路线传参:

路线三:函数本身快照

相当于装饰器施工团队,可以直接获取你这套房子本身的一些属性,比如名字,说明等。也就是函数的__name__和__doc__等等一大堆__开头的属性。

图片

看上图,在装饰器中打印了下函数a的固有属性,发现都可以正常打印。

结果有的同学就说了,这第三种路线传参,是不是就是通过更改赋值函数a本身的属性来让装饰器拿到新的数据?

咱试一下,把a函数的__doc__属性更改,看看怎么样?

图片

如图可以看到,无论你怎么在函数内修改函数的属性,但是装饰器都更早的时候已经写死了属性,相当于提前照了快照,所以不会产生变化,所以这条路线传参数是不行的。

这就好比,你毛坯房都交给装修团队了,加钱也谈好了,结果你又自己临时变卦,把房子的固有属性-比如面积扩大一倍,然后钱不给人家增加,装修团队当然不认了。

好了,本期结束,欢迎大家关注实测系列,都是博主的头脑风暴的结果哦~