装饰器是一个用于封装函数或类的代码的工具。它显式地将封装器应用到函数或类上,从而使它们选择加入到装饰器的功能中。对于在函数运行前处理常见前置条件(例如确认授权),或在函数运行后确保清理(例如输出清除或异常处理)装饰器都非常有用。对于处理已经被装饰的函数或类本身,装饰器也很有用。例如,装饰器可以将函数注册到信号系统,或者注册到Web应用程序的URI注册表中。

    本文将概要介绍什么是装饰器,以及装饰器如何与 Python的函数和类交互。

1.1理解装饰器

    究其核心而言,装饰器就是一个可以接受调用也可以返回调用的调用。装饰器无非就是一个函数(或调用,如有_call_method_方法的对象),该函数接受被装饰的函数作为其位置参数。装饰器通过使用该参数来执行某些操作,然后返回原始参数或一些其他的调用(大概以这种方式与装饰器交互)由于函数在 Python中是一级对象,因此它们能够像其他对象一样被传递到另一个函数。装饰器就是接受另一个函数作为参数,并用其完成一些操作的函数。实际上这很容易理解。考虑下面一个非常简单的装饰器。它仅仅为被装饰的调用点字符串附加了一个字符串。
 def decorated_by(func):
 
   func. __doc__ +="\ Decorated by decorated_by"
   return func

现在,考虑下面这个普通的函数:
def add(x, y ):
  "'Return the sum of x and y'"
  return x +y
 
函数的 docstring是在第一行指定的字符串。假如在 Python的 Shell中对该函数运行Help命令,就能看到该字符串。下面是将装饰器应用到add函数的示例
def add(x, y): 
   "'return the sum of x and y "'
   return x +y
add=decorated_by(add)
 
以下是执行help命令得到的结果
Help on function add in module__main__:
add(x, y)
  Return the sum of x and y.
  Decorated by decorated_by
(END)
 这里发生了什么?其实就是装饰器修改了add函数的__doc__属性,然后返回原来的函数对象。
1.2装饰器语法

    大多数时候开发人员使用装饰器来装饰函数,他们只对装饰过的最终函数感兴趣,而对于未装饰函数的引用最终就变得多余,正因为如此(也是为了更整洁),所以定义函数,给它赋一个特定的名称,然后立刻将装饰过的函数赋给相同的名称就不可取.因此, Python为装饰器引入了特殊的语法。装饰器的应用是通过在装饰器的名称前放置一个@字符,并在被装饰函数声明之上添加一行(不包含隐式装饰器的方法签名)来实现的。

下面来看一下如何优先将 decorated_by装饰器应用到add方法:
@decorated_by
def add(x,y):
 "'Return the sum of x +y"'
   return x+y

     再次注意,这里没有给@ decorated_by提供方法签名。假设该装饰器有一个单独的位置参数,而这个参数是装饰过的方法(在某些情况下,会看到一个带有其他参数的方法签名)
该语法允许在声明函数的位置应用装饰器,从而代码更容易阅读并且可以立即意识到应用了装饰器。可读性很重要。
 

装饰器应用的顺序:

    何时应用装饰器?使用@语法时,在创建被装饰的可调用函数后,会立刻应用装饰器。因此以上两个示例中所展示的将 decorated_by应用到ad的方式几乎是一样的。首先创建add函数,然后立即使用 decorated_by将其封装起来。
    需要注意的重要一点是,对某个可调用函数,可以使用多个装饰器(就像可以多次封装函数调用一样)。
    但请注意,如果通过@语法使用多个装饰器,就需要按照自底向上的顺序来应用它们。起初觉得这违反直觉,但是恰恰说明了 Python 解释器实际所做的工作。
    考虑下面这个应用了两个装饰器的函数:
@also_decorated_by
@decorated_by
def add(x,y):
   "'Return the sum of x and y. ""
   return x+y
 
    首先发生的是由解释器创建add函数,然后应用 decorated_by装饰器。该装饰器返回了一个可调用函数(正如所有装饰器做的一样),该函数被发送给also_ decorated_by装饰器,also_decorated_by也做了同样的事情,接下来结果被赋给add函数。
    切记,装饰器 decorated_by的应用程序与下面的代码在语法上是相同的:
 

add=decorated_by(add)

    前面两个装饰器示例与下面的代码在语法上相同
 

add =also_decorated_by(decorated_by(add))

 
    在这两种情况下,读取代码时首先读到装饰器also_decorated_by。但是,装饰器的应用是自底向上的,这与函数的解析(由内向外)是相同的。工作也采用同样的原则。

    在传统的函数调用情况下,解释器一定首先解析内部函数调用,以便有合适的对象或值发送给外部调用。
       add=also_decorated_by(decorated_by(add)) #First, get a return value for
                                          #decorated_by(add)
        add = also decorated_by(decorated_by(add))#Send that return value to
                                           #also decorated b
    
     有了装饰器后,通常首先创建add函数。

    @also_decorated_by
    @decorated_by
    def add(x, y):
       "'teturn the sum sf x and Y."'
       return x+y
 
    然后,调用装饰器@ decorated_by,并将其作为add函数的装饰方法。
    @also_decorated_by
    @decorated_by
    def add(x, y):
        "'Return the sum of x and y."'
        return x+y
 
    @decorated_by函数返回自己的可调用函数(在本例中,是add的修改版本)。该返回值在最后步骤发送给@also_decorated_by。
    @also_decorated_by
    @decorated_by
    def add(x, y):
        "'Return the sum of x and y."'
        return x+y
    应用装饰器时需要记住一件重要的事情,即装饰器的应用是自底向上的。很多时候,顺序非常重要。

1.3在何处使用装饰器
    Python标准库中包括很多包含装饰器的模块,并且很多常用工具和框架利用它们实现常用功能。
    例如,如果要使一个类上的方法不需要这个类的实例,可以使用@classmethod或@staticmethod装饰器,它们是标准库的一部分。mock模块(用于单元测试,在 Python3.3以后被添加到标准库中)允许使用@mock. patch或@mock. patch. object作为装饰器。
    一些常见工具也使用装饰器。 Django(用于 Python的常见Web框架)使用@login_required作为装饰器,允许开发人员指定用户必须登录オ能査看一个特定页面,并且使用@ permission_ required应用更具体的权限限制。Fask(另一个常见的Web框架)使用@app. route充当指定的URI与浏览器访问这些URI时所运行的函数之间的注册表。
    Celery(常见的 Python任务运行工具)使用复杂的@task装饰器来标识函数是否为异步任务。该装饰器实际上返回Task类的实例,用来阐明如何使用装饰器制作一个方便的APl;

python语言中的装饰器详解的更多相关文章

  1. python设计模式之装饰器详解(三)

    python的装饰器使用是python语言一个非常重要的部分,装饰器是程序设计模式中装饰模式的具体化,python提供了特殊的语法糖可以非常方便的实现装饰模式. 系列文章 python设计模式之单例模 ...

  2. C#中的 Attribute 与 Python/TypeScript 中的装饰器是同个东西吗

    前言 最近成功把「前端带师」带入C#的坑(实际是前端带师开始从cocos转unity游戏开发了) 某天,「前端带师」看到这段代码后问了个问题:[这个是装饰器]? [HttpGet] public Re ...

  3. Python装饰器详解

    python中的装饰器是一个用得非常多的东西,我们可以把一些特定的方法.通用的方法写成一个个装饰器,这就为调用这些方法提供一个非常大的便利,如此提高我们代码的可读性以及简洁性,以及可扩展性. 在学习p ...

  4. python之装饰器详解

    这几天翻看python语法,看到装饰器这里着实卡了一阵,最初认为也就是个函数指针的用法,但仔细研究后发现,不止这么简单. 首先很多资料将装饰器定义为AOP的范畴,也就是Aspect Oriented ...

  5. Python中的各种装饰器详解

    Python装饰器,分两部分,一是装饰器本身的定义,一是被装饰器对象的定义. 一.函数式装饰器:装饰器本身是一个函数. 1.装饰函数:被装饰对象是一个函数 [1]装饰器无参数: a.被装饰对象无参数: ...

  6. Python—装饰器详解

    装饰器:(语法糖) 本质是函数,它是赋予函数新功能,但是不改变函数的源代码及调用方式   原则: 1.不能修改被装饰函数的源代码 2.不能修改被装饰函数的调用方式 3.函数的返回值也不变 这两点简而言 ...

  7. python装饰器1:函数装饰器详解

    装饰器1:函数装饰器 装饰器2:类装饰器 装饰器3:进阶 先混个眼熟 谁可以作为装饰器(可以将谁编写成装饰器): 函数 方法 实现了__call__的可调用类 装饰器可以去装饰谁(谁可以被装饰): 函 ...

  8. Python全栈开发之8、装饰器详解

    一文让你彻底明白Python装饰器原理,从此面试工作再也不怕了.转载请注明出处http://www.cnblogs.com/Wxtrkbc/p/5486253.html 一.装饰器 装饰器可以使函数执 ...

  9. python函数装饰器详解

    python装饰器(fuctional decorators)简单来说就是修改其他函数的函数. 这样的函数需要满足两个个条件: 1.不能修改原函数的源代码 2.不能改变原函数的调用方式 需要达到的效果 ...

  10. python 叠加装饰器详解

    def out1(func1): #7.func1=in2的内存地址,就是in2 print('out1') def in1(): #8.调用函数index() 因为函数在in1里,所以首先运行in1 ...

随机推荐

  1. TomCat 的 Jenkins 提示:你的容器没有使用UTF-8解码URL地址

    1.编辑 Linux 系统的 Tomcat 安装目录的 conf 目录的 server.xml 文件 2.在 <Connector> 追加内容 URIEncoding="UTF- ...

  2. 从 Linux 内核角度探秘 JDK MappedByteBuffer

    本文涉及到的内核源码版本为: 5.4 ,JVM 源码为:OpenJDK17,RocketMQ 源码版本为:5.1.1 在之前的文章<一步一图带你深入剖析 JDK NIO ByteBuffer 在 ...

  3. 记录--两行CSS让页面提升了近7倍渲染性能

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言 对于前端人员来讲,最令人头疼的应该就是页面性能了,当用户在访问一个页面时,总是希望它能够快速呈现在眼前并且是可交互状态.如果页面加载 ...

  4. ET介绍——数值组件设计

    类似魔兽世界,moba这种技能极其复杂,灵活性要求极高的技能系统,必须需要一套及其灵活的数值结构来搭配.数值结构设计好了,实现技能系统就会非常简单,否则就是一场灾难.比如魔兽世界,一个人物的数值属性非 ...

  5. 从零开始学Spring Boot系列-集成MyBatis-Plus

    在Spring Boot应用开发中,MyBatis-Plus是一个强大且易于使用的MyBatis增强工具,它提供了很多实用的功能,如代码生成器.条件构造器.分页插件等,极大地简化了MyBatis的使用 ...

  6. #线段树#洛谷 4588 [TJOI2018]数学计算

    题目传送门 分析 由于曾经做过原题 所以就直接说了,因为每个数最多被除掉一次 所以可以用线段树维护区间乘,也就很简单了,删除就单点修改就行了 代码 #include <cstdio> #i ...

  7. #Tarjan#洛谷 1407 [国家集训队]稳定婚姻

    题目 分析 如果婚姻安全那么两个点不在同一个强连通分量, 考虑强制定方向,夫妻女向男连边,情侣男向女连边, 这样就直接用Tarjan有向图缩点就可以了 代码 #include <iostream ...

  8. 深入理解 SQL UNION 运算符及其应用场景

    SQL UNION运算符 SQL UNION运算符用于组合两个或多个SELECT语句的结果集. 每个UNION中的SELECT语句必须具有相同数量的列. 列的数据类型也必须相似. 每个SELECT语句 ...

  9. Numpy的数组对象

    数组对象 NumPy 最重要的一个特点是其 N 维数组对象 ndarray,它是一系列同类型数据的集合,从0 开始进行集合中元素的索引:ndarray 对象是用于存放同类型元素的多维数组,其中的每个元 ...

  10. 利用BCEL字节码构造内存马

    ****# 前言 BCEL加载类有一个特点,只可以加载jdk原生的类,其它框架的类,都会报错ClassnotFound的错误.但是,BCEL的ClassLoader在8u252后被删除了 注入流程分析 ...