如何使用Python装饰器Decorator

技术如何使用Python装饰器Decorator本篇内容介绍了“如何使用Python装饰器Decorator”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧

本文介绍了“如何使用Python Decorator”的知识。很多人在实际案例的操作中会遇到这样的困难。让边肖带领你学习如何处理这些情况。希望大家认真阅读,学点东西!

1. 叠加使用Python装饰器

最近有同学问,Python也有类似Java的@xxxx语法。这到底是什么意思?我现在回答这个问题。

Java中的@xxxx语法是一个Annotation,而Python中的@xxxx语法是一个装饰器。虽然语法相似,但功能完全不同。Java注释相当于语法元素(方法、类、接口等)的元数据。).Python的装饰器是Python函数(方法)的包装器。现在我们举个例子。

@makebold @ maketalidefday(): return ' hello ' print(say())这段代码为函数say使用了两个修饰词:@ make bold和@makeitalic,它们处于叠加状态。@makeitalic将首先作用于say函数,然后@makebold将作用于@makeitalic装饰器的结果,该装饰器将say函数返回的字符串与...和.因此这段代码的执行结果如下:

Hello

但是,直接执行这段代码肯定会出错,因为这两个装饰器还没有定义。让我们看看如何定义这两个装饰者。

2. 定义Python装饰器

装饰器本身是一个普通的Python函数,只是函数的参数需要是函数类型(通常传递到装饰函数中),定义形式如下:

BiHello/i/b I/b现在定义了前面给出的两个装饰者:

from functoolimportwrapsedfmakebold(fn): @ wrapps(fn)defmakebold _ wrapped(* args,*kwargs):return'b' fn(*args,* kwargs)'/b ' returnmakebold _ wrapped defmake italic(fn): @ wrapps(fn)defmake italic _ wrapped(* args,**kwargs)3360 return ' I ' fn(* args,* * kwargs)'这使用了包装功能,可以省略,但会有一些副作用。

使用@makebold和@makeitalic修改函数时,修改后的函数会传递给makebold函数和makeitalic函数,也就是说fn参数就是修改后的函数。在外部调用修饰函数时,实际上是调用装饰器返回的函数,即makebold_wrapped和makeitalic_wrapped,这将导致修饰函数的属性发生变化,比如函数名和函数文档。现在,您可以首先移除@ wraps并执行以下代码:

@ make italic @ makeboldefsay():返回' hello' print(说。_ _ name _ _) #输出函数名将输出以下内容:

Makebold_wrapped,因为最终使用了@m。

akebold装饰器,所以输出的是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()  # 输出函数本身 # 输出:<function getTalk.<locals>.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”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/36825.html

(0)

相关推荐

  • c#的ScaleOPC.DLL功能有哪些

    技术c#的ScaleOPC.DLL功能有哪些本篇内容主要讲解“c#的ScaleOPC.DLL功能有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“c#的ScaleOPC.D

    攻略 2021年11月26日
  • sparksql查询的数据保存(sparksql命令行怎么保存数据)

    技术Spark SQL数据加载和保存的实例分析今天就跟大家聊聊有关Spark SQL数据加载和保存的实例分析,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。一、前置

    攻略 2021年12月17日
  • 如何分析python在键值对的数据集合Dict

    技术如何分析python在键值对的数据集合Dict如何分析python在键值对的数据集合Dict,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。dict是

    攻略 2021年12月4日
  • php发验证码

    技术php发验证码 php发验证码php实现发送验证码功能的方法:1、创建好HTML和js文件;2、创建“Msm.php”文件,内容为“public function sendmsm(){...}”;3

    礼包 2021年10月28日
  • MYSQL如何探索在非互联网企业中的读写分离架构

    技术MYSQL如何探索在非互联网企业中的读写分离架构MYSQL如何探索在非互联网企业中的读写分离架构,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所

    攻略 2021年10月25日
  • 1元涨1000粉丝网站,抖音怎么刷粉最划算?

    技术1元涨1000粉丝网站,抖音怎么刷粉最划算?1元涨1000粉丝网站,抖音怎么刷粉最划算?在正常情况下,抖音1元涨1000粉丝是有难度的,如果量大,比如一次性加几万粉,抖音100元涨1000粉丝也是可以做的,毕竟量大从

    测评 2021年11月11日