Python函数装饰器(decorator)

装饰器(decorator)在你希望不修改函数本身的前提下扩展函数的功能时非常有用。decorator就像一个wrapper一样,在函数执行之前或者之后修改该函数的行为,而无需修改函数本身的代码,这也是装饰器名称的来由。

0. Python中@的用法

在介绍装饰器之前,先介绍一下Python中@的用法。
@是一个装饰器,针对函数,起调用传参的作用。@function作为一个装饰器,用来修饰紧跟着的函数(可以是另一个装饰器,也可以是函数定义)。

def funA(desA):
    print("It's funA")

@funA
def funC():
    print("It's funC")

输出结果为:

It's funA

这是因为:@funA 修饰函数定义def funC(),将funC()赋值给funA()的形参。执行的时候由上而下,先定义funA,然后运行funA(funC())。此时desA=funC(),然后funA()输出‘It's funA'

1. 原始状态装饰器

def get_text(name):
   return "lorem ipsum, {0} dolor sit amet".format(name)

def p_decorate(func):
   def func_wrapper(name):
       return "

{0}

".format(func(name)) return func_wrapper # 通过get_text=p_decorate(get_text)的方式覆盖了get_text从而形成了有新功能的同名函数 get_text = p_decorate(get_text) print get_text("John")

本质上,decorator就是一个返回函数的高阶函数。在上面的示例中,p_decorate是一个函数装饰器,通过get_text=p_decorate(get_text)的方式覆盖了get_text,从而形成了有新功能的同名函数。运行程序会输出:

Outputs lorem ipsum, John dolor sit amet

2. python 修饰符语法糖

def p_decorate(func):
   def func_wrapper(name):
       return "

{0}

".format(func(name)) return func_wrapper @p_decorate def get_text(name): return "lorem ipsum, {0} dolor sit amet".format(name) print get_text("John")

使用Python的@语法,把decorator置于函数的定义处,相当于执行get_text=p_decorate(get_text)。运行上面的程序,同样会输出:

Outputs lorem ipsum, John dolor sit amet

3. class method装饰器

python中类的方法是一个首参数为self指针的函数。我们可以和普通函数一样去做修饰,但是需要注意的是必须在wrapper函数中考虑self指针参数。

def p_decorate(func):
   def func_wrapper(self):
       return "

{0}

".format(func(self)) return func_wrapper class Person(object): def __init__(self): self.name = "John" self.family = "Doe" @p_decorate def get_fullname(self): return self.name+" "+self.family my_person = Person() print my_person.get_fullname()

一个更好的方案是调整代码使得我们的装饰器对于函数或者method同样适用。这可以通过通过将args和*kwargs放到wrapper函数中作为参数来实现,这样可以接受任意个数的参数或者keyword型参数。

def p_decorate(func):
   def func_wrapper(*args, **kwargs):
       return "

{0}

".format(func(*args, **kwargs)) return func_wrapper class Person(object): def __init__(self): self.name = "John" self.family = "Doe" @p_decorate def get_fullname(self): return self.name+" "+self.family my_person = Person() print my_person.get_fullname()

4. 向decorator传入参数

from functools import wraps

def tags(tag_name):
    def tags_decorator(func):
        # functools模块包含了wraps函数。wraps也是一个decorator,但是仅仅用于更新wrapping function(func_wrapper)的属性为原始函数的属性(get_text)
        @wraps(func)
        def func_wrapper(name):
            return "<{0}>{1}".format(tag_name, func(name))
        return func_wrapper
    return tags_decorator

@tags("p")
def get_text(name):
    return "Hello "+name

print get_text("John")

其中,functools模块的wraps函数也是一个decorator,但是仅仅用于更新wrapping function(func_wrapper)的属性为原始函数的属性(get_text)。

@tags("p") 相当于调用tags(tag_name="p"), 然后返回一个装饰器tags_decorator。然后相当于运行 get_text = tags_decorator(func= get_text)

运行后会输出:

Outputs 

Hello John

更多干货,欢迎关注个人博客:http://mochi.website/

你可能感兴趣的:(Python函数装饰器(decorator))