美文网首页
python装饰器

python装饰器

作者: 壁花烧年 | 来源:发表于2017-06-12 14:42 被阅读0次

装饰器是程序开发中经常会用到的一个功能,功能就是在运行原来功能基础上,加上一些其它功能,比如权限的验证,比如日志的记录等等。不修改原来的代码,进行功能的扩展。
比如java中的动态代理,python的注解装饰器。
其实python的装饰器,是修改了代码。
装饰器的工作原理:

def outer(fn):
    print('...outer...')

    def inner():
        print('...inner...')
        fn()

    return inner


def test():
    print('...test...')

test = outer(test)
print('*'*15)
test()

结果如下:


装饰器原理结果.jpg

装饰器就是引用了闭包的概念。装饰器的工作原理如下:


装饰器原理.jpg
现在采用装饰器:
def outer(fn):
    print('...outer...')

    def inner():
        print('...inner...')
        fn()

    return inner


@outer                       #就相当于 test = outer(test)
def test():
    print('...test...')

test()

输出结果如下:


装饰器结果.jpg

多个装饰器:

def f1(fn):
    def f1_inner():
        return '<b>'+fn()+'</b>'
    return f1_inner

def f2(fn):
    def f2_inner():
        return '<i>'+fn()+'</i>'
    return f2_inner

@f1
@f2
def fun():
    return 'hello world!'

print(fun())

结果如下:

多个装饰器结果.jpg

装饰器主要的功能有:
引入日志
函数执行时间统计
执行函数前预备处理
执行函数后清理处理
权限检验等场景
缓存
之前演示的装饰器都是无参调用的,装饰器的传参是如何实现的:

def f1(fn):
    def f2(a,b):
        print(a,b)
        fn(a,b)
    return f2


@f1
def fun(a, b):
    print(a+b)

fun(10, 20)

输出结果如下:


装饰器传参结果.jpg

这样把参数写死显然不适合装饰器的普遍性,如果有不同参数的函数调用该装饰器,如何改写装饰器:

from time import ctime, sleep


def f1(fn):
    def f2(*args, **kwargs):
        print('%s call at %s'%(fn.__name__, ctime()))
        print(*args, **kwargs)
        fn(*args, **kwargs)
    return f2


@f1
def fun1(a, b):
    print(a+b)
@f1
def fun2(a, b, c):
    print(a+b+c)

fun1(10, 20)
sleep(2)
fun2(30, 40, 50)

结果如下:


不定长传参结果.jpg

以上举得被装饰器装饰过的函数都是直接打印,如果是想返回的值的函数使用该装饰器,那装饰器又不具备普遍性,修改装饰器如下:

from time import ctime, sleep


def f1(fn):
    def f2(*args, **kwargs):
        print('%s call at %s'%(fn.__name__, ctime()))
        return fn(*args, **kwargs)
    return f2


@f1
def fun1(a, b):
    print(a+b)
@f1
def fun2(a, b, c):
    return a+b+c

fun1(10, 20)
sleep(2)
print(fun2(30, 40, 50))

结果如下:

return装饰器结果.jpg
如果闭包中的f2没有return fn(args,kwargs)而是直接fn(args,**kwargs),最后打印得到的结果是None。
装饰器带参数,在原有装饰器的基础上,设置外部变量。
from time import ctime, sleep

def timefun_arg(pre="hello"):
    def timefun(func):
        def wrappedfunc():
            print("%s called at %s %s"%(func.__name__, ctime(), pre))
            return func()
        return wrappedfunc
    return timefun

@timefun_arg("wangcai")
def foo():
    print("I am foo")

@timefun_arg("python")
def too():
    print("I am too")

@timefun_arg()
def coo():
    print("I am coo")

foo()
sleep(2)

too()
sleep(2)

coo()

输出结果如下:

带参数的装饰器.jpg
装饰器函数其实是这样一个接口约束,它必须接受一个callable对象作为参数,然后返回一个callable对象。在Python中一般callable对象都是函数,但也有例外。只要某个对象重写了 call() 方法,那么这个对象就是callable的。
类装饰器:
class Dog():
    def __init__(self, fun):
        self.__fun = fun

    def __call__(self, *args, **kwargs):
        print('...call...')
        return self.__fun(*args, **kwargs)

@Dog                       #foo = Dog(foo)
def foo():
    print('...foo...')

@Dog
def foo1(a, b):
    print('...foo1...')
    return a+b


foo()
print(foo1(1,2))

结果如下:

类装饰器结果.jpg
当用Dog来装作装饰器对foo函数进行装饰的时候,首先会创建Dog的实例对象
并且会把foo这个函数名当做参数传递到init方法中,即在init方法中的fun变量指向了foo函数体,foo函数相当于指向了用Dog创建出来的实例对象。当在使用foo()进行调用时,就相当于让这个对象(),因此会调用这个对象的call方法。为了能够在call方法中调用原来foo指向的函数体,所以在init方法中就需要一个实例属性来保存这个函数体的引用,所以才有了self.__fun = fun这句代码,从而在调用call方法中能够调用到foo之前的函数体。

相关文章

  • 装饰器模式

    介绍 在python装饰器学习 这篇文章中,介绍了python 中的装饰器,python内置了对装饰器的支持。面向...

  • python中的装饰器

    python装饰器详解 Python装饰器学习(九步入门) 装饰器(decorator) 就是一个包装机(wrap...

  • [译] Python装饰器Part II:装饰器参数

    这是Python装饰器讲解的第二部分,上一篇:Python装饰器Part I:装饰器简介 回顾:不带参数的装饰器 ...

  • Python中的装饰器

    Python中的装饰器 不带参数的装饰器 带参数的装饰器 类装饰器 functools.wraps 使用装饰器极大...

  • Python进阶——面向对象

    1. Python中的@property   @property是python自带的装饰器,装饰器(decorat...

  • Python 装饰器填坑指南 | 最常见的报错信息、原因和解决方

    Python 装饰器简介装饰器(Decorator)是 Python 非常实用的一个语法糖功能。装饰器本质是一种返...

  • Python装饰器

    Python装饰器 一、函数装饰器 1.无参装饰器 示例:日志记录装饰器 2.带参装饰器 示例: 二、类装饰器 示例:

  • python3基础---详解装饰器

    1、装饰器原理 2、装饰器语法 3、装饰器执行的时间 装饰器在Python解释器执行的时候,就会进行自动装饰,并不...

  • 2019-05-26python装饰器到底是什么?

    装饰器例子 参考语法 装饰器是什么?个人理解,装饰器,是python中一种写法的定义。他仍然符合python的基本...

  • 2018-07-18

    Python装饰器 装饰,顾名思义,是用来打扮什么东西的。Python装饰...

网友评论

      本文标题:python装饰器

      本文链接:https://www.haomeiwen.com/subject/nmokqxtx.html