Python – 装饰器(Decorator)

什么情况下可以使用装饰器:函数可以作为参数传递的语言,可以使用装饰?

装饰器的好处:可以极大地简化代码,在不改变原函数的基础上动态修改函数功能,避免每个函数写重复性代码.(可以让已有函数不做任何改动的情况下增加功能.可以使修改函数更加容易,本质上还是一个函数)经常用于以下方面:

1、打印日志 @log

2、检测性能 @performance

3、数据库事务 @transaction

4、URL路由 @post

例:一个只打印“hello”的函数,我们需要再加上“world”;

def addworld(func):
    def addFun():
        return func()+"world"
    return addFun

def printHello():
    return"hello"
print(printHello())

world = addworld(printHello)
print(world())

print Hello函数内部不做任何修改,但在使用修改后的函数时,需要一个world接受addWorld的返回值,把world指向addFun,再调用world(),这个过程较复杂.所以可以:

def addworld(func):
    def addFun():
        return func()+" world"
    return addFun

@addworld
def printHello():
    return "hello"

print(printHello())

只需要在需要修改的函数前加一个@addworld,调用方式还是和以前的一样.如果一个函数有两个装饰器:

def addworld(func):
    print("===装饰器1===")
    def addFun():
        return func()+" world"
    return addFun
def addHaha(func):
    print("===装饰器2===")
    def addFun():
        return func()+" haha"
    return addFun

@addHaha
@addworld
def printHello():
    print("===hello==")
    return "hello"

print(printHello())

当Python的解释器执行到@addHaha时,会将下一行的函数,进行装饰,但下一行为@addWorld,所以解释器需要把@addworld先进行装饰.运行的结果就是,先把addworld运行完成的返回值作为参数传递到addHaha中.带参数的装饰器:

def addNum(func):
    def addFun(*args, **kwargs):
        ret = func(*args, **kwargs)*2
        return ret
    return addFun

@addNum
def printSum(a, b):
    return a+b

i = printSum(7, 7)
print(i)

返回两个数的和的两倍,带参数的装饰器的通用模式:

def fun(funName):
    def fun1(*args, **kwargs):
        ret =funName(*args, **kwargs)
        return ret
    return fun1

在原有基础上添加一个外部变量,在原有的装饰器外再添加一个函数:

def addNum1(c):
    def addNum(func):
        def addFun(*args, **kwargs):
            ret = func(*args, **kwargs)*2*c
            return ret
        return addFun
    return addNum
@addNum1(5)
def printSum(a, b):
    return a+b
print(printSum(7, 7))
addNum1()

可用在插入日志、性能测试、事务处理、缓存、权限校验等场景.下面是一个日志功能的装饰器

from functools import wraps

deflog(label):

defdecorate(func):

@wraps(func)

def_wrap(*args,**kwargs):

try:

func(*args,**kwargs)

print("name",func.__name__)

except Exceptionase:

print(e.args)

return_wrap

returndecorate

@log("info")

deffoo(a,b,c):

print(a+b+c)

print("infoo")

#decorate=decorate(foo)

if__name__==‘__main__‘:

foo(1,2,3)

#decorate()