设为首页 加入收藏

TOP

Python装饰器深入全面理解(二)
2019-09-03 02:48:29 】 浏览:109
Tags:Python 装饰 深入 全面 理解
有关键字参数以字典的形式参数在变量名为kwargs的字典中。


当我们知道只有位置参数,但不知道有多少个位置参数是func装饰器可以这么写:


输出结果:


do_something函数开始运行……


你好,姚明!


do_something函数结束运行……


-------------------------------


do_something_2函数开始运行……


你好,姚大明!


你好,姚小明!


do_something_2函数结束运行……


-------------------------------


do_something_3函数开始运行……


你好,姚一明!


你好,姚二明!


你好,姚三明!


你好,姚四明!


do_something_3函数结束运行……


上面例子定义func装饰器时,我们用*name来接受任意个数的位置参数,可别以为只能用*args,args只是一个变量名,只不过约定俗成,用的多一些,实际开发时你爱取啥名就用啥名,对于这个知识点不再多说,毕竟本篇主角是装饰器。我们继续装饰器内容!


当我们知道只有关键字参数,却不知道参数个数时,可以func装饰器这么写:


输出结果:


do_something函数开始运行……


你好,姚明!


do_something函数结束运行……


-------------------------------


do_something_2函数开始运行……


你好,姚大明!


你好,姚小明!


do_something_2函数结束运行……


-------------------------------


do_something_3函数开始运行……


你好,姚一明!


你好,姚二明!


你好,姚三明!


你好,姚四明!


do_something_3函数结束运行……


事实上,大多数情况下,我们对被装饰函数是一无所知的——我们不知道有多少个位置参数、多少个关键字参数,甚至对有没有位置参数、关键字参数都不知道,这时候,我们就只能*args和**kwargs齐上阵了:


输出结果:


do_something函数开始运行……


你好,姚明!


do_something函数结束运行……


-------------------------------


do_something_2函数开始运行……


你好,姚大明!


你好,姚小明!


do_something_2函数结束运行……


-------------------------------


do_something_3函数开始运行……


你好,姚一明!


你好,姚二明!


你好,姚三明!


你好,姚四明!


do_something_3函数结束运行……


我们上面写的装饰器都没有参数,或者说只有一个自带参数,也就是被装饰函数f。其实,装饰器也是可以有其他参数的,这样的装饰器更加灵活。我们通过实例来说明:现在我们要对上面的func装饰器进行改进,需要做到灵活控制装饰器是用中文输出还是用英文输出,代码如下。


输出如下:


do_something函数开始运行……


你好,姚明!


do_something函数结束运行……


-------------------------


The function of do_something_2 starts runging…


你好,姚明!


The function of do_something_2 ends runging…


可以看到,通过装饰器带参数的方式,我们只需要在定义被装饰函数时,指定装饰器参数,就可以灵活控制每个被装饰函数提示的语言。


当然,必须承认,装饰器带参数后,看起来更加复杂,需要多嵌套一层函数,由最外层的函数接受参数,里层函数才是真正的装饰器。使用装饰器时,会首先运行带参数的最外层函数,返回装饰器,这一步Python会自动帮我们完成。所以,带参数的装饰器甚至可以这么使用:


装饰器也是可以多层嵌套使用的,也就是说,一个函数可以通过是被多个装饰器所装饰,执行顺序是从下到上的优先顺序加载装饰:


输出结果:


1


4


7


5


6


2


3


8


9


inner_timmer函数开始运行……


开始计时……


你好,姚明!


开始结束……


do_something函数运行时长为:1.0004358291625977秒


inner_timmer函数结束运行……


-------------------------


5


6


2


3


inner_timmer函数开始运行……


开始计时……


你好,姚明!


开始结束……


do_something_2函数运行时长为:1.000028133392334秒


inner_timmer函数结束运行……


在上面代码中,我们同时用func和timmer两个装饰器来装饰do_something,从运行结果中可以看出,两个装饰器都发挥了作用。同时,为了方便大家理解,我们使用不带@符号的来使用两个装饰器装饰,两者运行结果是一样的,结合代码中的输出标记,我们来分析一下装饰器的执行过程:开始运行后,1->4->7这几个过程我相信大家都是可以理解的,到了位置7后,遇到了@符号标识的装饰器,而且是多层的,两个@装饰器相当于func(timmer(do_something_2)),所以是先执行timmer函数获取返回值作为参数传递给func,所以有了7之后是5->6,timmer函数返回值是inner_timmer函数,这时候就相当于func(inner_timmer),所以程序退出timmer函数后进入func函数,就有了2->3,从func函数返回后,继续向下执行遇到位置8,然后就进入了主函数运行,所以是8->9,此时的函数是被装饰过的,本质已经是func函数返回的inner_func函数了,所以最终在主函数中执行do_something时执行的是inner_func方法,所以先输出了func装饰器的函数开始提示,然后才是timmer装饰器的计时开始提示。


嗯,有点复杂!


通过上面的介绍,我想你已经知道,@符号是装饰器的一个表示,或者说一个装饰器语法糖,当使用@时,例如@A,这种语法糖会自动将被装饰函数f作为参数传递给A函数,然后将A函数的返回值重新f给f这个变量名,这就是@语法糖帮我们做的事情,概括来说就是f=A(f)()。


我们现在发散一下思维,假设A如果是一个类会怎么样呢?我们知道当A是一个类时,A()表示调用A类的构造函数__init__实例化一个A类对象,那么A(f)就表示将函数f作为参数传递给A类的构造方法__init__来构造一个A类实例对象,如果使用了@符号,那么这种语法机制就还会在A(f)后面加一个括号变成A(f)(),这是什么鬼?执行一个类实例对象?不过话要说回来,如果A(f)()这种结构要是没有问题,能够成功执行,是不是就意味着Python中类也可以成为装饰器了呢?确实如此。我们先看看通过A()()执行一个类实例对象会怎么样:


输出结果:


实例化一个A类对象


__call__方法被调用……


看到没,通过A()()执行一个类实例对象时,执行的是A类内部的__call__方法。那么如果用A用作装饰器时,@A返回的就是A类内部定义的__call__方法,相当于函数装饰器func内的inner_func。来,我们感受一下类装饰器:


输出结果:


实例化一个A类对象……


do_something函数开始运行……


你好,姚明!


do_something函数结束运行……


如果类装饰器带参数呢?这时候,类装饰器的参数也

首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Shell脚本应用 - 条件测试操作 下一篇Shell脚本应用 - for、while循环..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目