装饰器

Posted ipython-201806

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了装饰器相关的知识,希望对你有一定的参考价值。

定义

    装饰器本质上就是一个python函数,可以让其他函数在不需要做任何代码变动的前提下,增加额外的功能。装饰器的返回值也是一个函数对象。

装饰器种类

不带参数的装饰器

技术分享图片
import time


def timer(func):
    def inner():
        start = time.time()
        time.sleep(0.2)
        func()
        print(time.time() - start)
    return inner


@timer          # ===> func1 = timer(func1)
def func1():
    print("in func1")


func1()
不带参数的装饰器

带参数的装饰器

技术分享图片
import time


def timer(func):
    def inner(*args, **kwargs):
        start = time.time()
        time.sleep(0.2)
        func(*args, **kwargs)
        print(time.time() - start)
    return inner


@timer        # ===> func1 = timer(func1)
def func1(a):
    print(a)


func1("hello")
带参数装饰器

带返回值的装饰器

技术分享图片
import time


def timer(func):
    def inner(*args, **kwargs):
        start = time.time()
        time.sleep(0.2)
        ret = func(*args, **kwargs)
        print(time.time() - start)
        return ret
    return inner


@timer        # ===> func1 = timer(func1)
def func1(a, b):
    print("in func1")


@timer        # ===> func2 = timer(func2)
def func2(a):
    print("in func2 and get a:%s" % (a))
    return "func2 over"


func1("hello", "world")
print(func2("aaaa"))
带返回值的装饰器

    当查看函数信息的方法时,在此处失效:

技术分享图片
import time


def timer(func):
    def inner(*args, **kwargs):
        start = time.time()
        time.sleep(0.2)
        ret = func(*args, **kwargs)
        print(time.time() - start)
        return ret
    return inner

@timer
def index():
    """这是一个主页信息"""
    print("from index")


print(index.__doc__)
print(index.__name__)


# 结果:
None
inner
查看函数注释、函数名时失效

    解决方案:

技术分享图片
import time
from functools import wraps


def timer(func):
    @wraps(func)
    def inner(*args, **kwargs):
        start = time.time()
        time.sleep(0.2)
        ret = func(*args, **kwargs)
        print(time.time() - start)
        return ret
    return inner


@timer
def index():
    """这是一个主页信息"""
    print("from index")


print(index.__doc__)
print(index.__name__)


# 结果:
这是一个主页信息
index
解决查看函数注释、函数名等失效问题

开放封闭原则

    装饰器完美的遵循了 开放封闭原则

对扩展开放

    任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以必须允许代码扩展、添加新功能。

对修改封闭

    我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候对其进行修改,很有可能影响其他已经在使用该函数的用户。

装饰器的固定结构

技术分享图片
def timer(func):
    def inner(*args, **kwargs):
        """执行函数之前要做的"""
        ret = func(*args, **kwargs)
        """执行函数之后要做的"""
        return ret
    return inner
装饰器固定格式
技术分享图片
from functools import wraps


def timer(func):
    @wraps(func)
    def inner(*args, **kwargs):
        """执行函数之前要做的"""
        ret = func(*args, **kwargs)
        """执行函数之后要做的"""
        return ret
    return inner
装饰器固定格式-wraps版

装饰器带参数

    应用场景:如果有成千上万个函数使用了一个装饰器,现在想把这些装饰器取消掉

技术分享图片
def outer(flag):
    def timer(func):
        def inner(*args, **kwargs):
            if flag:
                print("执行函数之前要做的")
            ret = func(*args, **kwargs)
            if flag:
                print("执行函数之后要做的")
            return ret
        return inner
    return timer


@outer(False)
def func():
    print(111)


func()
装饰器带参数

多个装饰器装饰一个函数

技术分享图片
def wrapper1(func):   # func = f
    def inner1():
        print("wrapper1, before func")
        func()
        print("wrapper1, after func")
    return inner1


def wrapper2(func):  # func = inner1
    def inner2():
        print("wrapper2, before func")
        func()
        print("wrapper2, after func")
    return inner2


@wrapper2    # f = wrapper2(f) ===> f = inner2
@wrapper1    # 先装饰wrapper1 ---> f = wrapper1(f) ===> f = inner1
def f():
    print("in f")


f()   # ===> inner2()
多个装饰器装饰一个函数

    规律:

    对于n个装饰器装饰同一个函数,例如靠近函数名f的为@outer_1,最上层为@outer_n,那么执行f()时,执行顺序为:

  • 第n个装饰器执行f()前要做的 ---> 第n-1个装饰器执行f()前要做的 ---> ...--->第1个装饰器执行f()前要做的 --->
  • f() --->
  • 第1个装饰器执行f()要做的 ---> 第二个装饰器执行f()后要做的 --->...--->第n个装饰器执行f()后要做的

以上是关于装饰器的主要内容,如果未能解决你的问题,请参考以下文章

Python面向对象学习之八,装饰器

thymeleaf 片段渲染后重新加载 javascript

代码缺乏装饰?使用ts装饰器来装饰你的代码

代码缺乏装饰?使用ts装饰器来装饰你的代码

代码缺乏装饰?使用ts装饰器来装饰你的代码

代码缺乏装饰?使用ts装饰器来装饰你的代码