python装饰器简介

python装饰器的概念建立在python中,一切皆是对象的基础上。正是因为一切皆是对象,所以函数可以作为参数传入,可以添加函数的功能。

装饰器简单来说就是对函数进行修饰,多用于添加函数的功能。接受和处理函数对象。企业级应用中最常用到,比如引入日志,增加性能检测功能,事务处理能力等等。

下面一步步来理解装饰器

1. 首先是最简单的python函数

def foo():
    print "I am foo"

2. 传入函数对象作为参数

def deco(func):
    print "I am deco, before %s called" %func.__name__
    func()  
    print "I am deco, after %s called" %func.__name__

    return func

这里deco已经有点装饰器的意思了,因为它接受一个函数对象func作为参数,在运行func的前后打印信息。试想,如果把print换成一些日志,或者统计功能,则实现了对func调用时添加了功能的目的。

最后将这个函数对象又作为返回值传递出去

3. 装饰自己

def deco(func):
    print "I am deco, before %s called" %func.__name__
    func()  
    print "I am deco, after %s called" %func.__name__

    return func

def foo():
    print "I am foo"

foo = deco(foo)

foo()

这里foo用deco装饰,或者说调用了自己。本质上是foo指向了deco函数对象,这样我们在调用foo时,感觉除了打印两行信息,好像没什么区别,达到了统一调用的目的。

上述就实现了一个基本的装饰器功能,而python2.4之后,开始使用@语法糖来表示装饰器

4. @装饰器

def deco(func):
    print "I am deco, before %s called" %func.__name__
    func()  
    print "I am deco, after %s called" %func.__name__
    return func

@deco
def foo():
    print "I am foo"

foo()

在函数定义的上面,写上@+装饰器的名称,表示用该装饰器装饰这个函数,类似3中的函数包装。

@语句本质上就是执行

foo = deco(foo)

5. 内嵌包装函数来返回函数对象

def deco(func):
    # 内嵌函数
    def _wrapped():
        print "I am deco, before %s called" %func.__name__
        func()  
        print "I am deco, after %s called" %func.__name__
    return _wrapped

@deco
def foo():
    print "I am foo"

foo()

将4中deco函数的动作封装到一个内嵌函数中,内嵌包装函数的形参和返回值与原函数相同,装饰器函数则返回内嵌包装函数对象。

因为4中在@装饰过程中执行了print,而这个过程是在函数定义过程中,也就是定义过程中就要执行print,这在很大程度上是不符合编程目的的。所以我们可以把这一动作用内嵌函数包装起来,这样print就只会在函数调用过程中执行。也能确保每次新函数都能被调用

6. 带参数的函数进行装饰

def deco(func):
    # 内嵌函数
    def _wrapped(a, b):
        print "I am deco, before %s called" %func.__name__
        func(a, b)  
        print "I am deco, after %s called" %func.__name__
    return _wrapped

@deco
def foo(a,b):
    print "I am foo: %d" %(a+b)

foo()

因为被装饰的函数带参数,所以我们必须想办法把参数传递给它,所以就规定:内嵌函数的形参和返回值必须和被装饰函数相同,而装饰函数返回内嵌函数对象

这样我们在调用foo(a,b)的是,等价与调用_wrapped(a, b)

7. 对参数不确定的函数进行装饰

def deco(func):
    # 内嵌函数
    def _wrapped(*args, **kw):
        print "I am deco, before %s called" %func.__name__
        func(*args, **kw)   
        print "I am deco, after %s called" %func.__name__
    return _wrapped

@deco
def foo1(a,b):
    print "I am foo: %d" %(a+b)


@deco
def foo2(a,b,c):
    print "I am foo: %d" %(a+b+c)

foo1()
foo2()

参数用(*args, **kw),自动适应变参和命名参数,可以让装饰器更加灵活,能够装饰更多的函数

8. 装饰器参数

def deco(args):
    def _realDeco(func):
        # 内嵌函数
        def _wrapped(*args, **kw):
            print "deco args: %s" %args
            print "I am deco, before %s called" %func.__name__
            func(*args, **kw)   
            print "I am deco, after %s called" %func.__name__
        return _wrapped

    return _realDeco

@deco("hello")
def foo1(a,b):
    print "I am foo: %d" %(a+b)


@deco("world")
def foo2(a,b,c):
    print "I am foo: %d" %(a+b+c)

foo1()
foo2()

要想让装饰器传入参数,则必须在外层再加一层包装。

以上就是装饰器的基本用法,更多用法可以参考官方文档。

你可能感兴趣的:(Python)