如何使用Python装饰器Decorator
本篇内容介绍了“如何使用Python装饰器Decorator”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
创新互联公司从2013年开始,是专业互联网技术服务公司,拥有项目网站建设、网站设计网站策划,项目实施与项目整合能力。我们以让每一个梦想脱颖而出为使命,1280元治多做网站,已为上家服务,为治多各地企业和个人服务,联系电话:028-86922220
1. 叠加使用Python装饰器
最近有学员问,Python中也有与Java类似的@xxxx语法,这到底是什么意思呢?现在我就来回答这个问题。
Java中的@xxxx语法是注解(Annotation),而Python中的@xxxx语法是装饰器(decorator),尽管在语法上类似,但作用完全不同。Java的注解相当于语法元素(方法、类、接口等)的元数据。而Python的装饰器是对Python函数(方法)的包装,现在我们来举个例子。
@makebold @makeitalic def say(): return "Hello" print(say()))
这段代码,对函数say使用了2个装饰器:@makebold和@makeitalic,而且是叠加状态。@makeitalic会首先作用于say函数,然后@makebold会作用于@makeitalic装饰器的结果,这两个装饰器分别用...和...包装say函数返回的字符串,所以这段代码的执行结果如下:
Hello
不过直接执行这段代码肯定会出错的,这是因为这两个装饰器还没定义,下面就看下如何定义这两个装饰器。
2. 定义Python装饰器
装饰器本身就是一个普通的Python函数,只是函数的参数需要是函数类型(通常传入被装饰的函数),定义形式如下:
Hello
现在就来定义前面给出的两个装饰器:
from functools import wraps def makebold(fn): @wraps(fn) def makebold_wrapped(*args, **kwargs): return "" + fn(*args, **kwargs) + "" return makebold_wrapped def makeitalic(fn): @wraps(fn) def makeitalic_wrapped(*args, **kwargs): return "" + fn(*args, **kwargs) + "" return makeitalic_wrapped
很明显,makebold和makeitalic是两个普通的Python函数,而且在函数内部分别定义了另外两个函数,而且这两个函数被作为返回值返回。这其中使用了wraps函数,这个函数其实可以不加,不过会有一些副作用。
由于使用@makebold和@makeitalic修饰某个函数时,会将这个被修饰的函数传入makebold函数和makeitalic函数,也就是说,fn参数就是这个被修饰的函数。而在外部调用这个被修饰函数时,实际上是调用了修饰器返回的函数,也就是makebold_wrapped和makeitalic_wrapped,这样就会导致被修饰函数属性的改变,如函数名、函数文档等,现在可以先去掉@wraps,执行下面的代码:
@makeitalic @makebold def say(): return "Hello" print(say.__name__) # 输出函数名
会输出如下的内容:
makebold_wrapped
由于最后使用了@makebold装饰器,所以输出的是makebold函数返回的makebold_wrapped函数的名字。如果加上@wraps,那么就会输出say。
要注意,需要通过装饰器方式调用wraps函数,这样其实就相当于在@makebold外面又包了一层装饰器(wraps)。
3. 理解Python函数
现在我们已经了解了如何自定义Python装饰器,但应该如何理解装饰器呢?到底是什么原理呢?要想理解Python装饰器,首先应该知道Python函数就是对象,看下面的例子:
def shout(word="yes"): return word.capitalize() # 输出:Yes print(shout()) # 将shout函数赋给另一个变量,这里并没有使用圆括号, # 所以不是调用函数,而是将函数赋给另一个变量,也就是为函数起一个别名 scream = shout # 可以用scream调用shout函数 # 输出:Yes print(scream()) # 目前,同一个函数,有两个引用:scream和shout,可以使用del删除一个引用 del shout try: # 该引用删除后,就不能通过该引用调用函数了 print(shout()) except NameError as e: print(e) # 仍然可以通过另外一个引用调用函数 # 输出:Yes print(scream())
这段代码演示了把函数作为对象使用。如果加一对圆括号,就是调用函数,如果不加一对圆括号,函数就是对象,可以赋给另一个变量,也可以作为函数参数值传入函数。
由于Python函数本身是对象,所以可以在任何地方定义,包括函数内容,这就是Python内建函数,代码如下:
def talk(): # 内嵌函数 def whisper(word="YES"): return word.lower()+"..." # 调用内嵌函数 print(whisper()) # 调用talk,whisper函数在talk内部被调用 # 输出:yes... talk() try: # 但whisper函数在talk函数外部并不可见,所以调用会哦抛出异常 print(whisper()) except NameError as e: print(e)
现在来总结下,Python函数的特性如下:
(1)可以将函数本身赋给一个变量,或作为参数值传入函数(方法);
(2)可以在一个函数(方法)内部定义;
有了这两个特性,就意味着函数可以被另一个函数返回,看下面的代码:
def getTalk(kind="shout"): # 定义第1个内嵌函数 def shout(word="yes"): return word.capitalize()+"!" # 定义第2个内嵌函数 def whisper(word="yes") : return word.lower()+"..." # 根据参数值返回特定的函数 if kind == "shout": # 这里没有使用一对圆括号,所以不是调用函数,而是返回函数本身 return shout else: return whisper # talk是函数本身,并没有被调用 talk = getTalk() # 输出函数本身 # 输出:.shout at 0x7f93a00475e0> print(talk) # 调用talk函数(其实是shout函数) print(talk()) #outputs : Yes! # 调用whisper函数 print(getTalk("whisper")())
在这段代码中,getTalk函数根据kind参数的值返回不同的内嵌函数,所以getTalk函数的返回值是函数本身,或称为函数对象,如果要调用函数,需要使用一对圆括号,如getTalk()()。
根据这一特性,我们还可以做更多事,例如,在调用一个函数之前自动完成其他工作,看下面的代码:
def doSomethingBefore(func): print("I do something before then I call the function you gave me") print(func()) doSomethingBefore(talk)
其实这段代码用doSomethingBefore函数包装了talk,这样可以通过doSomethingBefore函数调用talk函数,并在调用talk函数之前输出一行文本。
4. Python装饰器的原理
理解了Python函数,再理解Python装饰器就容易得多了。废话少说,先看下面的代码:
# 装饰器函数,参数是另一个函数(被装饰的函数) def my_shiny_new_decorator(a_function_to_decorate): # 装饰器的内嵌函数,用来包装被修饰的函数 def the_wrapper_around_the_original_function(): # 在调用被修饰函数之前输出一行文本 print("Before the function runs") # 调用被装饰函数 a_function_to_decorate() # 在调用被修饰函数之后输出一行文本 print("After the function runs") # 返回包装函数 return the_wrapper_around_the_original_function # 这个函数将被my_shiny_new_decorator函数修饰 def a_stand_alone_function(): print("I am a stand alone function, don't you dare modify me") # 调用函数 a_stand_alone_function() # 修饰a_stand_alone_function函数 a_stand_alone_function_decorated = my_shiny_new_decorator(a_stand_alone_function) a_stand_alone_function_decorated()
执行这段代码,会输出如下内容:
I am a stand alone function, don't you dare modify me Before the function runs I am a stand alone function, don't you dare modify me After the function runs
在这段代码中,通过my_shiny_new_decorator函数修饰了a_stand_alone_function函数,并在调用a_stand_alone_function函数前后各输出了一行文本。其实这就是Python装饰器的作用:包装函数。只是这里并没有使用装饰器的语法,而是用了最朴素的方式直接调用了装饰器函数来修饰a_stand_alone_function函数。
如果用装饰器来修饰a_stand_alone_function函数,那么可以用下面的代码。
@my_shiny_new_decorator def a_stand_alone_function(): print("I am a stand alone function, don't you dare modify me")
这时再调用a_stand_alone_function函数,就会自动使用my_shiny_new_decorator函数对a_stand_alone_function函数进行包装,也就是说,@my_shiny_new_decorator是my_shiny_new_decorator(a_stand_alone_function)的简写形式。
“如何使用Python装饰器Decorator”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注创新互联网站,小编将为大家输出更多高质量的实用文章!
当前文章:如何使用Python装饰器Decorator
本文链接:http://hbruida.cn/article/gddodj.html