博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python学习笔记012——装饰器
阅读量:6249 次
发布时间:2019-06-22

本文共 5037 字,大约阅读时间需要 16 分钟。

1 装饰器

1.1装饰器定义

在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)

1.2 装饰器分类

装饰器:函数装饰器,类装饰器,函数的装饰器,类的装饰器

装饰器:函数装饰函数,函数装饰类,类装饰函数,类装饰类(两者不是一一对应关系,其实我也不知道他们之间是什么样的对应关系)

一般而言,主要应用的是函数装饰函数

1.3 装饰器本质

本质上,decorator就是一个返回函数的高阶函数

在面向对象(OOP)的设计模式中,decorator被称为装饰模式。OOP的装饰模式需要通过继承组合来实现,

而Python除了能支持OOP的decorator外,直接从语法层次支持decorator。

Python的decorator可以用函数实现,也可以用类实现。

1.4 装饰器目的

在不改变对象名的情况下,丰富原对象的功能

1.5 装饰器的作用

1)多个函数对象需要添加同一个功能,将该功能写成一个函数,该函数就是装饰函数,在任何函数需要该功能时则直接调用该函数即可,也即,我们用装饰函数对其装饰

2)被装饰的函数我们称之为功能函数,所以功能函数在装饰后,尽管函数内容发生了改变,但是功能函数的名还需要保留。

 

 

2 装饰器应用实例

该部分主要分为:

简单装饰器,功能函数中带有返回值的装饰函数,多个功能函数中参数个数不固定的装饰器,带参数的装饰器,装饰器的嵌套

简而言之:

简单装饰器,功能函数带返回值的解决办法,功能函数参数不定的解决办法,装饰器中参数的解决办法,装饰器的嵌套解决办法

2.1 装饰器雏形

实例:

def fun1(fun2):    print("befor fun1 called")    fun2()    print("after fun1 called")    return fun2def fun3():    print("fun3 called")fun3()fun1(fun3)

输出:

fun3 called befor fun1 calledfun3 calledafter fun1 called

在这里,功能函数为 fun3 ,装饰器为 fun1 

在原本功能函数中增加了两个输出代码。

在代码中,注意区分 fun3 与 fun3() 之间的关系: fun3理解成函数变量, fun3()理解成函数调用。采用 id() 判断id位置即可验证。

为了更说明问题,我们同时验证测试 fun1与 fun1()之间的关系

def fun1(fun2):    print("befor fun1 called")    fun2()    print("after fun1 called")    return fun2def fun3():    print("fun3 called")fun3()print("---------------------")fun1(fun3)print("---------------------")print(id(fun3))print("---------------------")print(id(fun3()))print("---------------------")print(id(fun1))print("---------------------")print(id(fun1()))

输出:

fun3 called---------------------befor fun1 calledfun3 calledafter fun1 called---------------------140504457497728---------------------fun3 called10748000---------------------140504482160424---------------------Traceback (most recent call last):  File "test0.py", line 20, in 
print(id(fun1()))TypeError: fun1() missing 1 required positional argument: 'fun2'

此时,我们可以明确两个问题

1) fun3 与 fun3() 不是一个概念, fun3 为函数变量, fun3() 是函数调用。

2)在 fun1() 中的形参 fun2  仅仅传递了函数参数,没有调用 fun2() ,所以在调用 fun1() 时执行函数内代码时才调用了 fun2() 

 

另外:这里并没有完全实现装饰器的作用,仅是简单的一个装饰器演示,因被装饰器修改后,调用原功能函数时并没有改变其函数内容

2.2 简单装饰器

def fun1(fun2):    def fun4():        print("befor fun1 called")        fun2()        print("after fun1 called")    return fun4@fun1 #fun3=fun1(fun3)def fun3():    print("fun3 called")print(fun3())

输出

befor fun1 calledfun3 calledafter fun1 calledNone

注:

1)在输出最后出现 None ,主要是因为 fun3() 函数(经过装饰后)没有返回值(也可以理解成返回值为空)。

     将 print(fun3()) 修改为 fun3() ,则就不会输出 None 

2) @fun1 表示 fun3 = fun1(fun3) ,但是不能被描述为等同于 fun3() = fun1(fun3) ,注意区分 fun3与 fun3()之间的关系

2.3 功能函数中带有返回值

def fun1(fun2):    def fun4():        print("befor fun1 called")        a = fun2()        print("after fun1 called")        return a    return fun4@fun1 #fun3=fun1(fun3)def fun3():    print("fun3 called")    return "YES"fun3print("---------------------1")fun3()print("---------------------2")print(fun3)print("---------------------3")print(fun3())

输出:

---------------------1befor fun1 calledfun3 calledafter fun1 called---------------------2
.fun4 at 0x7f930b77e048>---------------------3befor fun1 calledfun3 calledafter fun1 calledYES

解决返回值的时候,其实就是先在装饰器函数接受功能函数中的返回值,再在装饰器中将该返回值 return 

2.4 功能函数参数个数确定的解决办法

def fun1(fun2):    def fun4(m,n):        print("befor fun1 called")        a = fun2(m,n)        print("after fun1 called")        return a    return fun4@fun1 #fun3=fun1(fun3)def fun3(i,j):    print("fun3 called")    return i * jprint(fun3(2,3))

输出:

befor fun1 calledfun3 calledafter fun1 called6

2.5 功能函数参数个数不确定的解决办法

def fun1(fun2):    def fun4(*m,**n):        print("befor fun1 called")        a = fun2(*m,**n)        print("after fun1 called")        return a    return fun4@fun1 #fun3=fun1(fun3)def fun3(i,j):    print("fun3 called")    return i + j@fun1def fun5(i,j,k):    print("fun5 called")    return i + j + kprint(fun3(1,2))print(fun5(1,k=2,j=3))

输出:

befor fun1 calledfun3 calledafter fun1 called3befor fun1 calledfun5 calledafter fun1 called6

采用元组字典混合形式可以将所有可变参数一网打尽

2.6装饰器中参数的解决办法

有时候需要在装饰器中增加参数,解决的办法就是在原装饰器的最外层多增加一层函数嵌套即可

def fun6(args):    def fun1(fun2):        def fun4(*m,**n):            print("befor fun1 called:[%s]"%args)            a = fun2(*m,**n)            print("after fun1 called >> %s"%args)            return a        return fun4    return fun1# fun1 = fun6("耕毅的学习笔记")# fun4 = fun1(fun3)# fun3 = fun4#综上所述可以简写为# fun3 = fun6('耕毅学习笔记')(fun3)@fun6("耕毅学习笔记")def fun3(i,j):    print("fun3 called")    return i + j@fun6("耕毅练习笔记")def fun5(i,j,k):    print("fun5 called")    return i + j + kprint(fun3(1,2))print(fun5(1,k=2,j=3))

输出:

befor fun1 called:[耕毅学习笔记]fun3 calledafter fun1 called >> 耕毅学习笔记3befor fun1 called:[耕毅练习笔记]fun5 calledafter fun1 called >> 耕毅练习笔记6

2.7 装饰器的嵌套解决办法

如果一个装饰器满足功能函数需求,则可以增加一个装饰器再对其修饰。   该种方法不常用

def fun1(fn):    print("fun1 called")def fun2(fn):    print("fun2 called")@fun1@fun2def fun3():    print("fun3 called")fun3()

输出

deco2 is calleddeco1 is calledTraceback (most recent call last):  File "test0.py", line 28, in 
myfun()TypeError: 'NoneType' object is not callable

1)该段代码说明装饰器也可以嵌套,嵌套关系

1 @fun2 fun3 = fun2(fun3)2 @fun1 fun3 = fun2(fun3)

该嵌套关系先执行  @fun2  再执行 @fun1 

 


 

其实在装饰器概念中含有了“闭包”内容。

 

转载地址:http://ovysa.baihongyu.com/

你可能感兴趣的文章
[转]Intel C++编译器的预定义宏(Windows版、Linux版)
查看>>
***测试02------查点总结
查看>>
1Z0-052 中英文解析(2)
查看>>
Android accessibility service detect notification
查看>>
调度器状态机的单片机上用的小系统
查看>>
Windows7与Window2008 64位IIS7上面DCOM配置Excel、Word等
查看>>
绘画与照片修饰
查看>>
Google Adwords关键词即将告别完全精确匹配
查看>>
原生JavaScript文件上传带进度条
查看>>
kong 负载均衡
查看>>
linux快捷键
查看>>
Bugzilla提Bug
查看>>
MySql执行sql文件
查看>>
MongoDB一对多存储
查看>>
日本ZBrush大师 岡田恵太/Keita Okada 作品欣赏
查看>>
android环境那此事--genymotion, virtualbox
查看>>
centreon分布式监控
查看>>
linux常用命令-date-clock-hwclock-type-whatis--help-man-info-cal
查看>>
笔记之sed工具
查看>>
MySQL5.7 GTID与传统快速切换
查看>>