关于python 装饰器

关于装饰器

无参装饰器

普通函数

def say_hello(*args, **kwargs):                       
    print 'hello world'

无参装饰器

def debug(func):                       # debug为装饰器,func为要被装饰的函数
    def wrapper(*args, **kwargs):      
        # 此处的args,kwargs承接func函数的参数,使用wrapper替换func
        # 装饰器最内层的函数为被装饰函数的替换函数,参数列表必须和被装饰函数相同
        print "[DEBUG]: enter {}()".format(func.__name__)
        return func(*args, **kwargs)           # 调用被装饰的func函数
    return wrapper

装饰器调用,原始方法

say_hello = debug(say_hello)  # 添加功能并保持原函数名不变

等价于 语法糖 方式调用

@debug
def say_hello():
    print "hello!"

对于有参装饰器

def debug(flag):            
    # 通过语法糖方式 @debug(flag=True)调用后才获取到了wrapper函数,然后才是使用wrapper再次装饰(无参形式)func函数
    def wrapper(func):
        def inner(*args,**kwargs):
            print "[DEBUG]: enter {}()".format(func.__name__)
            return func(*args, **kwargs)
        return inner
    return wrapper

语法糖 方式调用

@debug(flag=True)
def say_hello():
    print "hello!"

等价于

wrapper = debug(flag=True)   # wrapper 是一个函数
say_hello = wrapper(say_hello)  # wrapper相当 debug(say_hello)的功能

类方法的函数装饰器

类方法的函数装饰器和函数的函数装饰器类似

对于类方法来说,都会有一个默认的参数self,它实际表示的是类的一个实例,所以在装饰器的内部函数inner也要传入一个类实例的参数,其他的用法都和函数装饰器相同。
如:

def debug(flag):            
    def wrapper(func):
        def inner(instance,  *args, **kwargs):  #  类方法的函数装饰器的装饰函数参数列表必须和被装饰的函数一样,故第一个参数必须为等同于类方法的self的类实例
            print "[DEBUG]: enter {}()".format(func.__name__)
            return func(instance,  *args, **kwargs)
        return inner
    return wrapper

装饰:

class Method(object):

    @debug(flag=False)
    def func(self, args, kwargs):
        time.sleep(0.8)

functools.wraps()函数

打印装饰后的 say_hello 函数的 __name__

print(say_hello.__name__)

输出: inner

造成被装饰函数自身的信息丢失,可以使用functools.wraps()解决该问题

from functools import wraps

def debug(flag):            
    def wrapper(func):
        @wraps(func) 
        def inner( *args, **kwargs):  
            print "[DEBUG]: enter {}()".format(func.__name__)
            return func(*args, **kwargs)
        return inner
    return wrapper
print(say_hello.__name__)

输出: say_hello

装饰器调用顺序

无参装饰器

def dec1(func):
    print "AAAAA"
    def inner(*args, **kwargs):
        print "BBBBB"
        func(*args, **kwargs)

    return inner

def dec2(func):
    print "CCCCC"
    def inner(*args, **kwargs):
        print "DDDDD"
        func(*args, **kwargs)

    return inner

@dec1
@dec2
def test():
    pass

test()

输出为:

CCCCC
AAAAA
BBBBB
DDDDD

因为等价于

test = dec2(test)   # 输出 CCCCC
test = dec1(test)   # 输出 AAAAA

test()                     # 输出BBBBB DDDDD

带参装饰器

def dec1(*args):
    print "11111"
    def wrapper(func):
        print "AAAAA"
        def inner(*args, **kwargs):
            print "BBBBB"
            func(*args, **kwargs)
        return inner
    return wrapper

def dec2(*args):
    print "22222"
    def wrapper(func):
        print "CCCCC"
        def inner(*args, **kwargs):
            print "DDDDD"
            func(*args, **kwargs)
        return inner
    return wrapper

@dec1()
@dec2()
def test():
    pass

test()

输出为:

11111
22222
CCCCC
AAAAA
BBBBBB
DDDDD

因为等价于

wrapper1 = dec1()        # 输出 11111
wrapper2 = dec2()        # 输出 22222


# 类似无参的情况
@wrapper1
@wrapper2
def test():
    pass

test()                            # 输出 CCCCC AAAAA BBBBBB DDDDD                          

猜你喜欢

转载自blog.csdn.net/pushiqiang/article/details/81198738