Python各种类型装饰器详细介绍

目录
  • 装饰器说明
  • 装饰器分类
    • 最简单的装饰器
    • 用于修改对象的装饰器
    • 用于模拟对象的装饰器--函数装饰器
    • 用于模拟对象的装饰器--类方法装饰器
    • 用于模拟对象的装饰器--类装饰器
    • 特殊应用的装饰器
    • 类实现的装饰器
    • 装饰带参数/返回值的对象
    • 装饰器带参数
  • 装饰器应用

装饰器说明

Python中的装饰器是一种可以装饰其它对象的工具。该工具本质上是一个可调用的对象(callable),所以装饰器一般可以由函数、类来实现。装饰器本身需要接受一个被装饰的对象作为参数,该参数通常为函数、方法、类等对象。装饰器需要返回一个对象,该对象可以是 经过处理的原参数对象、一个包装且类似原参数的对象;或者返回一个不相干内容(通常不建议使用)

相信通过上述一段文字的描述,大家应该更加的迷惑了!所以下面我们就结合代码来理解Python中的装饰器。

装饰器分类

最简单的装饰器

def warp(obj):
    return obj

没错!!!这就是最简单的装饰器,并且是一个没有任何用处的装饰器。但是它确实是一个装饰器,并且可以用的很好。比如:

@warp    # 等价于 foo = warp(foo)
def foo():
    print('hello decorator!')

foo()    # => hello decorator!

而上面使用了装饰器的代码,其实我们可以通过其它方式达到相同的效果。具体见下:

def foo():
    print('hello decorator!')

foo = warp(foo)
foo()    # => hello decorator!

So,通过最简单的代码,我们可以发现装饰器其实就是接受了一个函数(对象),并且返回了一个函数(对象)的函数(可调用对象)。

用于修改对象的装饰器

在理解了装饰器的含义之后,再来看一个稍微有点作用的装饰器。代码如下:

def warp(obj):
    obj.name = 'python'
    return obj

这个装饰器在上一个例子的基础上,只添加了一行代码,但是却有了实际的作用。它的作用就是给被装饰的对象,添加一个name属性并且设置值为python。这个装饰器的使用效果如下:

@warp        # => Bar = warp(Bar)
class Bar(object):
    def __init__(self):
        pass

print(Bar.name)     # => python

可以看到实际的使用过程中,warp装饰器已经成功的给Bar对象添加了name属性。除了给类对象添加属性之外,它还可以给函数对象添加属性。

@warp       # => foo = warp(foo)
def foo():
    pass

print(foo.name)         # => python

用于模拟对象的装饰器--函数装饰器

上面例子中的装饰器,是直接修改了传入对象;而装饰器最常用的方式却是模拟一个传入对象。即返回一个和原对象相似的对象(即调用接口完全一样的另一个对象),并且该模拟对象是包装了原对象在内的。具体代码如下:

def outer(func):         # 函数装饰器
    def inner():
        func()

    return inner

上面是一个函数装饰器,即用来修饰函数的装饰器。因为它返回了一个模拟func对象的inner对象。而这里inner对象是一个函数,所以这个装饰器只能装饰函数。(因为inner对象只能模拟func这样的函数对象,不能模拟class对象)

@outer      # foo = outer(foo)
def foo():
    print('hello foo')

foo()    # => hello foo

上述代码中最后一行foo(),其实质上是执行的inner()。为了证明这一点,我们可以在inner中打印一条信息。并查看下foo的__name__属性。

def outer(func):         # 函数装饰器
    def inner():
        print('hello inner')
        func()

    return inner

@outer      # foo = outer(foo)
def foo():
    print('hello foo')

print(foo.__name__)
foo()

上述代码执行后的结果如下:

inner
hello inner
hello foo

可以看到首先打印的是 foo.__name__代码,注意内容是inner而不是foo(说明其本质上是inner函数);其次打印的时候,先打印inner函数中的内容,后打印foo函数中的内容。

用于模拟对象的装饰器--类方法装饰器

与函数装饰器类似的还有类方法装饰器,其作用相同,格式相近。只是些微有些区别,下面就是类方法装饰器的代码。

def outer(obj):         # 类方法装饰器
    def inner(self):
        print('hello inner')
        obj(self)

    return inner

class Zoo(object):
    def __init__(self):
        pass

    @outer        # => zoo = outer(zoo)
    def zoo(self):
        print('hello zoo')

zoo = Zoo()
print(zoo.zoo.__name__)
zoo.zoo()

可以看到类方法装饰器和函数装饰器,唯一的区别就是多了一个默认的self参数;这是因为类方法本身就比函数多这么一个参数。其执行的结果如下:

inner
hello inner
hello zoo

所以最后一行代码zoo.zoo函数执行的其实是inner函数。

用于模拟对象的装饰器--类装饰器

装饰器除了可以装饰函数、方法之外,还可以装饰器类对象。具体的代码如下:

def outer(clss):         # 类装饰器
    class Inner(object):
        def __init__(self):
            self.clss = clss()

        def __getattr__(self, attr):
            return getattr(self.clss, attr)

    return Inner

@outer          # Zoo = outer(Zoo)
class Zoo(object):
    def __init__(self):
        pass

    def say(self):
        print('hello world!')

zoo = Zoo()
print(zoo.__class__)    # <class '__main__.outer.<locals>.Inner'>
zoo.say()               # hello world!

通过代码可以看出,类装饰器与函数装饰器类似。即模拟一个与原参数接口一致的类对象。所以对于模拟类的装饰器,只能用在其可以模拟的对象之上,并不能互相修饰其它类型的对象。

特殊应用的装饰器

上面都是比较常规的装饰器,python中还有另外一些特殊的装饰器。比如:类静态属性装饰器。比如下面的代码:

class Foo(object):
    def __init__(self, height, weigth):
        self.height = height
        self.weigth = weigth

    @property
    def ratio(self):
        return self.height / self.weigth

foo = Foo(176, 120)
print(foo.ratio)    # => 1.4666666666666666

上述代码中的@property装饰器就是一个特殊的装饰器,它把ratio方法变成了一个属性。从最后一句调用代码可以看出,使用的是foo.ratio而不是foo.ratio()。

对于这类装饰器需要Python的特定属性和机制的支持才可以实现,不同特性的装饰器所需机制不同。如上述代码中的@property装饰器就可以使用下面的代码来实现。

class Prop(object):
    def __init__(self, fget):
        self.fget = fget

    def __get__(self, instance, owner):
        return self.fget(instance)

具体的使用效果如下:

class Foo(object):
    def __init__(self, height, weigth):
        self.height = height
        self.weigth = weigth

    @Prop
    def ratio(self):
        return self.height / self.weigth

foo = Foo(176, 120)
print(foo.ratio)    # => 1.4666666666666666

可以看到效果和原生的@property装饰器是一样的。

类实现的装饰器

在之前对于装饰器的说明中,有说道装饰器是一个callable对象。除了函数可以实现装饰器之外,还可以通过类来实现。那么类实现装饰器的具体代码如下:

class Warp(object):
    def __init__(self):
        pass

    def __call__(self, obj):
        obj.name = 'warp'
        return obj

这个类装饰器实现的功能,也是给传入的对象添加name属性,并设置其值为warp。其调用效果如下:

@Warp()
def foo():
    pass

print(foo.name)    # => warp

装饰带参数/返回值的对象

前面列举的所有例子,被装饰的对象都是无参数的。如果你需要装饰一个带参数的对象。那么就需要响应的修改下装饰器代码了。注意:这里特指那些模拟类型的装饰器。即函数装饰器、类方法装饰器、类装饰器。

假设我们先有一个带参数的函数,其内容如下:

def add(x, y):
    return x * y

如果使用原来的函数装饰器,肯定就会出错。主要因为这个函数带参数,并且也有返回值。而原来的函数装饰器则不能支持,原函数装饰器如下:

def outer(func):         # 函数装饰器
    def inner():
        func()

    return inner

可以看到inner模拟的仅仅是一个无参数、无返回值的对象。所以需要进行如下的修改:

def outer(func):         # 函数装饰器
    def inner(x, y):
        print('hello inner')
        return func(x, y)

    return inner

这样的函数装饰器就可以装饰add函数了。因为inner函数添加了x,y参数,调用func对象时也添加了参数,并且返回了func对象的返回值。具体使用效果如下:

@outer
def add(x, y):
    return x * y

print(add(2, 3))    # => 6

上述代码虽然可以实现add的装饰功能,但是如果现在我们在出现一个三个参数的函数需要装饰,或者一个带默认值参数的韩式需要装饰怎么办。我们不可能为没一个不同参数的函数都写一个相同功能的装饰器。所以终极的函数装饰器的写法如下:

def outer(func):         # 函数装饰器
    def inner(*args, **kwargs):
        print('hello inner')
        return func(*args, **kwargs)

    return inner

这里使用了python中动态参数的概念,这样装饰器就可以支持任意的组合参数的函数了。

装饰器带参数

上面说到的是被修饰的对象带参数的情况,还有一种情况就是装饰器本身希望支持带参数。这种情况类似于函数模块通过带参数可以更加灵活的道理一样。通过给装饰器带上参数,可以使得装饰器的功能更加的灵活。代码如下:

url_mapping = {}

def route(url):
    def decorator(func):         # 函数装饰器
        url_mapping[url] = func
        return func
    return decorator

上面是一个URL路由映射的装饰器,可以给不同的函数绑定不同的路由。如果装饰器不能带参数,则无法实现这样的功能。其使用效果如下:

@route('/home')
def home():
    pass

@route('/index')
def index():
    pass

print(url_mapping)  # => {'/home': <function home at 0x01DAD810>, '/index': <function index at 0x01DAD7C8>}

装饰器应用

Python装饰器的应用比较广泛,大部分场景的公共处理逻辑都可以使用装饰器去简化。(使用上类似于JAVA中的注解)一般比较常见的场景比如:

日志记录

权限验证单

例模式竞争

资源管理

到此这篇关于Python各种类型装饰器详细介绍的文章就介绍到这了,更多相关Python装饰器内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Python 函数装饰器应用教程

    目录 一.什么是函数装饰器 二.函数装饰器的执行时机 三.变量作用域 四.闭包 五.保留函数的元数据 七.使用lru_cache缓存函数执行结果 八.使用singledispatch实现泛型函数 九.通过参数控制函数装饰器的行为 一.什么是函数装饰器 1.函数装饰器是Python提供的一种增强函数功能的标记函数: 2.装饰器是可调用的函数对象,其参数是另一个函数(被装饰的函数): 我们可以使用修饰器来封装某个函数,从而让程序在执行这个函数之前与执行完这个函数之后,分别运行某些代码.这意味着,调用

  • Python装饰器详情

    目录 1.装饰器 1.1 应用场景 2.万能装饰器 3.多层装饰器 4.带参数的装饰器 1.装饰器 装饰器(Decorator):从字面上理解,就是装饰对象的器件.可以在不修改原有代码的情况下,为被装饰的对象增加新的功能或者附加限制条件或者帮助输出. 装饰器的特点是特点是函数是作为其参数出现的,装饰器还拥有闭包的特点. 示例代码如下所示: # 定义一个装饰器 def decorate(func): def wrapper(): func() print("已将学生加入学校学生名单")

  • 两个很实用的Python装饰器详解

    目录 1.超时函数 2.Trace函数 总结 1.超时函数 这个函数的作用在于可以给任意可能会hang住的函数添加超时功能,这个功能在编写外部API调用 .网络爬虫.数据库查询的时候特别有用 timeout装饰器的代码如下: import signal,functools #下面会用到的两个库 class TimeoutError(Exception): pass #定义一个Exception,后面超时抛出 def timeout(seconds, error_message = 'Functi

  • python 装饰器(Decorators)原理说明及操作代码

    目录 1 必要的2个核心操作 1.1 核心操作1, 函数内部可以定义函数 1.2 核心操作2 函数可以作为对象被输入输出 1.2.1 核心操作2的前置条件,函数是对象 1.2.2函数作为输入 1.2.3 函数作为输出 2 尝试构造装饰器 3装饰器定义的简写 本文目的是由浅入深地介绍python装饰器原理 装饰器(Decorators)是 Python 的一个重要部分 其功能是,在不修改原函数(类)定义代码的情况下,增加新的功能 为了理解和实现装饰器,我们先引入2个核心操作: 1 必要的2个核心操

  • Python各种类型装饰器详细介绍

    目录 装饰器说明 装饰器分类 最简单的装饰器 用于修改对象的装饰器 用于模拟对象的装饰器--函数装饰器 用于模拟对象的装饰器--类方法装饰器 用于模拟对象的装饰器--类装饰器 特殊应用的装饰器 类实现的装饰器 装饰带参数/返回值的对象 装饰器带参数 装饰器应用 装饰器说明 Python中的装饰器是一种可以装饰其它对象的工具.该工具本质上是一个可调用的对象(callable),所以装饰器一般可以由函数.类来实现.装饰器本身需要接受一个被装饰的对象作为参数,该参数通常为函数.方法.类等对象.装饰器需

  • Python装饰器详细介绍

    目录 装饰器 一.介绍 二.通过高阶函数+嵌套函数==>实现装饰器 1.变量知识回顾 2.高阶函数(装饰器前奏) 3.嵌套函数(装饰器前戏) 三.装饰器 1.装饰器 2.有参装饰器 3.终极装饰器 装饰器 一.介绍 器:代表函数的意思.装饰器本质就是是函数 功能:装饰其他函数,就是为其他函数添加附加功能 被装饰函数感受不到装饰器的存在 原则:  不能修改被装饰的函数的源代码(比如线上环境) 不能修改被装饰的函数的调用方式 实现装饰器知识储备:  函数即是“变量” 高阶函数 嵌套函数 高阶函数+嵌

  • Python中类型检查的详细介绍

    前言 大家都知道Python 是一门强类型.动态类型检查的语言.所谓动态类型,是指在定义变量时,我们无需指定变量的类型,Python 解释器会在运行时自动检查. 与静态类型语言(如 C 语言)相比,这不仅仅是少写了几个类型声明字符: #include <stdlib.h> #include <stdio.h> #define BUFF 100 char* greeting(char* name){ char* msg = (char *) malloc(sizeof(char) *

  • Python的装饰器详情介绍

    目录 1.定义及使用 2.@classmethod 1.定义及使用 例1:装饰器定义: def 装饰器函数(外部函数):            def 内联函数(*args,**kwargs):                ...前置装饰...                外部函数(*args,**kwargs)                ...后置装饰...            return 内联函数  例2:装饰器两种调用方式 第一种:装饰器函数(外部函数)(参数1,参数2....

  • python中的装饰器该如何使用

    目录 1. 需求是怎么来的 装饰器的定义很是抽象,我们来看一个小例子. def foo(): print('in foo()') foo() 这是一个很无聊的函数没错.但是突然有一个更无聊的人,我们称呼他为B君,说我想看看执行这个函数用了多长时间,好吧,那么我们可以这样做: import time def foo(): start = time.time() print('in foo()') time.sleep(2) end = time.time() print(f'used:{end -

  • Python 的lru_cache装饰器使用简介

    Python 的 lru_cache 装饰器是一个为自定义函数提供缓存功能的装饰器.其内部会在下次以相同参数调用该自定义函数时直接返回计算好的结果.通过缓存计算结果可以很好地提升性能. 1 从示例说起 假设我们有一个计算斐波那契数列的求和函数,其内部采用递归方式实现. from xxx.clock_decorator import clock @clock def fibonacci(n): if n<2: return n return fibonacci(n-2)+fibonacci(n-1

  • Python学习之装饰器与类的装饰器详解

    目录 装饰器 装饰器的定义 装饰器的用法 类中的装饰器 类的装饰器-classmethod 类的装饰器-staticmethod 类的装饰器-property 通过学习装饰器可以让我们更好更灵活的使用函数,通过学会使用装饰器还可以让我们的代码更加优雅. 在我们的实际工作中,很多场景都会用到装饰器,比如记录一些日志.或者屏蔽一些不太合法的程序执行从而使我们的代码更加安全. 装饰器 什么是装饰器?虽然对这个次感到陌生,但是完全不需要担心. 首先,装饰器也是一种函数:只不过装饰器可以接收 函数 作为参

  • 一篇文章带你了解Python中的装饰器

    目录 前言 Python 中的装饰器是什么 语法糖 使用 Python 装饰器修改函数行为 使用 Python 装饰器对函数进行计时 使用 Python 装饰器将有用信息记录到终端 Web app 中使用的装饰器 将参数传递给 Python 装饰器 使用多个 Python 装饰器 总结 前言 本文将带你学习装饰器在 Python 中的工作原理,如果在函数和类中使用装饰器,如何利用装饰器避免代码重复(DRY 原则,Don’t Repeat Yourself ). Python 中的装饰器是什么 装

  • Python中的装饰器用法详解

    本文实例讲述了Python中的装饰器用法.分享给大家供大家参考.具体分析如下: 这里还是先由stackoverflow上面的一个问题引起吧,如果使用如下的代码: 复制代码 代码如下: @makebold @makeitalic def say():    return "Hello" 打印出如下的输出: <b><i>Hello<i></b> 你会怎么做?最后给出的答案是: 复制代码 代码如下: def makebold(fn):    

  • python实现微信接口(itchat)详细介绍

    前言 itchat是一个开源的微信个人号接口,使用python调用微信从未如此简单.使用不到三十行的代码,你就可以完成一个能够处理所有信息的微信机器人.当然,该api的使用远不止一个机器人,更多的功能等着你来发现,比如这些.该接口与公众号接口itchatmp共享类似的操作方式,学习一次掌握两个工具.如今微信已经成为了个人社交的很大一部分,希望这个项目能够帮助你扩展你的个人的微信号.方便自己的生活. 安装 sudo pip install itchat 登录 itchat.auto_login()

随机推荐