美文网首页
Python函数装饰器(decorator)

Python函数装饰器(decorator)

作者: DongGuangqing | 来源:发表于2020-01-31 22:45 被阅读0次

    装饰器(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 "<p>{0}</p>".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,从而形成了有新功能的同名函数。运行程序会输出:

    <p>Outputs lorem ipsum, John dolor sit amet</p>
    

    2. python 修饰符语法糖

    def p_decorate(func):
       def func_wrapper(name):
           return "<p>{0}</p>".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)。运行上面的程序,同样会输出:

    <p>Outputs lorem ipsum, John dolor sit amet</p>
    

    3. class method装饰器

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

    def p_decorate(func):
       def func_wrapper(self):
           return "<p>{0}</p>".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 "<p>{0}</p>".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}</{0}>".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 <p>Hello John</p>
    

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

    相关文章

      网友评论

          本文标题:Python函数装饰器(decorator)

          本文链接:https://www.haomeiwen.com/subject/gptvhctx.html