python装饰器

我只是技术的搬运工

简介:对Python装饰器的一点个人理解

Python之装饰器

在这里用一个简单的例子分析Python的装饰器的过程:

import functools
def log(func=None, logger=None):
    if func is not None:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            if logger:
                logger.info(func.func_name + " will be called. (at A)")
            else:
                print(func.func_name + " will be called. (at a)")

            return func(*args, **kwargs)
        return wrapper

    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            if logger:
                logger.info(func.func_name + " will be called. (at B)")
            else:
                print(func.func_name + " will be called. (at b)")
            return func(*args, **kwargs)
        return wrapper
    return decorator

@log
def funcA(*args, **kwargs):
    print "funcA was called."

@log()
def funcB(*args, **kwargs):
    print "funcB was called."

funcA()
funcB()

#################output######################################

funcA will be called. (at a)
funcA was called.
funcB will be called. (at b)
funcB was called.

在分析这个例子之前,我们先来看看Python的装饰器的过程(个人理解):

@decorator
def func_name(*args, **kwargs):
    pass

在我们调用func_name()的时候,我们的调用逻辑过程,我认为是这样的:decorator(func_name)(*args, **kwargs)

现在我们回到上面的例子:

funcA() => log(funcA)(*args, **kwargs) => wrapper(*args, **kwargs)

funcB() => log()(funcB)(*args, **kwargs) = decorator(funcB)(*args, **kwargs) => wrapper(*args, **kwargs)

在最后都是调用wrapper,只是带参数的装饰器多调用了一层而已,为了得到返回值,我们一般是在wrapper调用func并返回func的执行结果。
我们搞清楚了这个过程之后,其实装饰器不止限定函数,装饰器也不止可以装饰函数了。

class log(object):
    def __init__(self, func=None):
        self.func = func

    def __call__(self,*args, **kwargs):
        print(self.func.func_name + " called. at log")
        return self.func(*args, **kwargs)

class logb(object):
    def __init__(self):
        pass

    def __call__(self, func):
        def wrapper(*args, **kwargs):
            print(func.func_name + " called. at logb")
            return func(*args, **kwargs)
        return wrapper

@log
def funcA():
    print "funcA called"

@logb()
def funcB():
    print "funcB called"

funcA()
funcB()

上面的例子的调用过程:

funcA() => log(funcA)(*args, **kwargs) => log(funcA).__call__(*args, **kwargs)
funcB() => logb()(funcB)(*args, **kwargs) => logb().__call__(funcB)(*args, *kwargs) => wrapper(*args, **kwargs)

只要理解了这个过程装饰器就很简单了。其实函数就是带有__call__的对象(个人理解),因此装饰器不仅可以装饰函数,还可以装饰类,不过个人感觉没什么作用,当然装饰器可以装饰类方法不过第一个参数必须得是self或是cls

注意:链式装饰器的装饰过程是由下往上装饰的。

@decorator_a
@decorator_b
def func(*args):
    pass

装饰过程是由下往上了,因此先是decorator_b(func)(*args),然后decorator_a(decorator_b(func))(*args)

你可能感兴趣的:(python)