Python装饰器的用法

装饰器

1.定义

装饰器函数本质是闭包(外部函数的返回值是内部函数的引用),为了运行时动态的增加功能,又不想改动原函数本身的代码和函数的调用方式

2.装饰器的原理

  • 功能函数foo,实现某个功能
def foo():
    print("This is func foo, doing somethings……")
  • 现在需要在不改变foo函数原有函数的代码和调用方式的情况下新增功能1,可以使用如下方式实现:
def decorator(func):
    def inner():
        func()
        print("This is add func, doing somethings else。。。。。")

    return inner


def foo():
    print("This is func foo, doing somethings……")


foo = decorator(foo)

if __name__ == '__main__':
    foo()
  • 以上实现方式的foo = decorator(foo)可以在原函数前加上@装饰器函数名实现,即@decorator
def decorator(func):
    def inner():
        func()
        print("This is add func, doing somethings else。。。。。")

    return inner


@decorator
def foo():
    print("This is func foo, doing somethings……")


if __name__ == '__main__':
    foo()

3.原函数带参数的装饰器实现

目标函数带有参数时,装饰器可以使用不定长参数来传递参数

def decorator(func):
    def inner(*args, **kwargs):
        func(*args, **kwargs)
        print("This is add func, doing somethings else。。。。。")

    return inner


@decorator
def foo(name):
    print("This is func foo, doing somethings and name is %s……" % name)


if __name__ == '__main__':
    foo('foo')

4.根据装饰器带有的参数不同执行不同的结果

有打印日志的和记录函数运行时间的装饰器函数,不传递参数默认不打印日至,传递不为False的参数来打印日志

import time


def decorator(log=0):
    def wrapper(func):
        def inner(*args, **kwargs):
            start_time = time.time()
            func(*args, **kwargs)
            time.sleep(1)
            end_time = time.time()
            runtime = end_time - start_time
            print("runtime is %.4fs。。。。。" % runtime)
            if log:
                print("Logging now ………………")

        return inner

    return wrapper


@decorator(1)
def foo(name):
    print("This is func foo, doing somethings and name is %s……" % name)


if __name__ == '__main__':
    foo('foo')

5.装饰器被调用的时间点

运行下面代码

def decorator(func):
    print("calling decorator……")

    def inner():
        func()
        print("This is add func, doing somethings else。。。。。")

    return inner


@decorator
def foo():
    print("This is func foo, doing somethings……")

运行上面代码发现打印了:calling decorator……
明装饰器外部函数在加载内存(或者导包)的第一时间就运行了,原因是@decorator等价于foo = decorator(foo),此处decorator被调用了

6.被装饰过的函数的函数名

运行下面代码

def decorator(func):
    def inner():
        func()
        print("This is add func, doing somethings else。。。。。")

    return inner


@decorator
def foo():
    print("This is func foo, doing somethings……")


if __name__ == '__main__':
    foo()
    print("The func foo's name is ", foo.__name__)

运行结果为:

This is func foo, doing somethings……
This is add func, doing somethings else。。。。。
The func foo's name is  inner

发现被装饰器装饰后foo函数的名称变为了inner

解决办法

  • 方法一:手动修改函数名称
def decorator(func):
    def inner():
        func()
        print("This is add func, doing somethings else。。。。。")
        inner.__name__ = func.__name__

    return inner


@decorator
def foo():
    print("This is func foo, doing somethings……")


if __name__ == '__main__':
    foo()
    print("The func foo's name is ", foo.__name__)

运行结果:

This is func foo, doing somethings……
This is add func, doing somethings else。。。。。
The func foo's name is  foo
  • 方法二:给inner函数加上functools模块的wraps装饰器函数,将原函数作为形参传入。
import functools


def decorator(func):
    @functools.wraps(func)
    def inner():
        func()
        print("This is add func, doing somethings else。。。。。")

    return inner


@decorator
def foo():
    print("This is func foo, doing somethings……")


if __name__ == '__main__':
    foo()
    print("The func foo's name is ", foo.__name__)

运行结果:

This is func foo, doing somethings……
This is add func, doing somethings else。。。。。
The func foo's name is  foo

7.多个装饰器装饰同一个函数

import functools


def decorator2(func):
    print("decorator2")

    @functools.wraps(func)
    def inner():
        func()
        print("This is add func2, doing somethings else。。。。。")

    return inner


def decorator1(func):
    print("decorator1")

    @functools.wraps(func)
    def inner():
        func()
        print("This is add func1, doing somethings else。。。。。")

    return inner


@decorator2
@decorator1
def foo():
    print("This is func foo, doing somethings……")


if __name__ == '__main__':
    foo()
    print("The func foo's name is ", foo.__name__)

运行结果:

decorator1
decorator2
This is func foo, doing somethings……
This is add func1, doing somethings else。。。。。
This is add func2, doing somethings else。。。。。
The func foo's name is  foo

先装饰的先执行,后装饰的后执行

@decorator2
@decorator1
等价于
foo = decorator2(decorator1(foo))

8.类装饰器

class DecoratorClass(object):

    def __call__(self, *args, **kwargs):
        return self.call_func

    def call_func(self):
        print("This is add func from class decorator……")


@DecoratorClass()
def foo():
    print("This is func foo, doing somethings……")


if __name__ == '__main__':
    foo()

运行结果:

This is add func from class decorator……

@DecoratorClass() 等价于 foo = DecoratorClass()(foo)
定于装饰器类时,重写对象的__call__方法,返回一个功能函数的引用即可。

猜你喜欢

转载自blog.csdn.net/lynnyq/article/details/79517814