美文网首页
Python语法糖 - 修饰器的使用

Python语法糖 - 修饰器的使用

作者: 戴文KeepLearning | 来源:发表于2020-03-10 17:20 被阅读0次

    装饰器本质上是一个 Python 函数或类,它可以让其他函数或类在不需要做任何代码修改的前提下增加额外功能,装饰器的返回值也是一个函数/类对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景,装饰器是解决这类问题的绝佳设计。有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码到装饰器中并继续重用。下面是一个简单的修饰器例子。

    # coding = utf-8
    
    import time
    from functools import wraps #知识点3注释
    
    def decorator_logging(func):
        @wraps(func) #知识点3注释
        def wraper(*args, **kwargs):
            print("%s is running now." % (func.__name__))
            return func(*args, **kwargs)
        return wraper
    
    def timec(func):
        @wraps(func) #知识点3注释
        def warper(*args, **kwargs):
            start = time.time()
            func(*args, **kwargs)
            end = time.time()
            print("%s function cost time: %f s" % (func.__name__, (end - start)))
        return warper
    
    @timec
    @decorator_logging
    def hi(name="Devin"):
        print("hello, " + name)
    
    if __name__ = '__main__':
        hi("Cat")
    

    记录一下上面这段代码,我觉得比较重要的知识点

    1. 这里面有两个修饰器decorator_loggingtimec。当有多个修饰器时,是先从内侧向外侧按顺序运行的。
    2. 装饰器在 Python 使用如此方便都要归因于 Python 的函数能像普通的对象一样能作为参数传递给其他函数,可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内。这个功能是通过参数*args、**kwargs实现的。
    3. 使用装饰器极大地复用了代码,但是他有一个缺点就是原函数的元信息不见了,比如函数的docstring__name__、参数列表等等,我们是通过第三方模块functools中的wraps修饰器来保存传递进装饰器中的func函数信息。如上段代码中知识点3的标记注释。

    还有一个比较有意思的是带参数的装饰器:

    def use_logging(level):
        def decorator(func):
            def wrapper(*args, **kwargs):
                if level == "warn":
                    logging.warn("%s is running" % func.__name__)
                elif level == "info":
                    logging.info("%s is running" % func.__name__)
                return func(*args)
            return wrapper
    
        return decorator
    
    @use_logging(level="warn")
    def foo(name='foo'):
        print("i am %s" % name)
    
    foo()
    

    上面的use_logging是允许带参数的装饰器。它实际上是对原有装饰器的一个函数封装,并返回一个装饰器。我们可以将它理解为一个含有参数的闭包。当我 们使用@use_logging(level="warn")调用的时候,Python 能够发现这一层的封装,并把参数传递到装饰器的环境中。
    @use_logging(level="warn")等价于@decorator

    类装饰器
    没错,装饰器不仅可以是函数,还可以是类,相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器主要依靠类的__call__方法,当使用@形式将装饰器附加到函数上时,就会调用此方法。

    class Foo(object):
        def __init__(self, func):
            self._func = func
    
        def __call__(self):
            print ('class decorator runing')
            self._func()
            print ('class decorator ending')
    
    @Foo
    def bar():
        print ('bar')
    
    bar()
    functools.wraps
    

    参考网页资料:

    1. 菜鸟教程 https://www.runoob.com/w3cnote/python-func-decorators.html
    2. 用于时钟计时的装饰器 https://blog.csdn.net/weixin_39549161/article/details/86110359

    相关文章

      网友评论

          本文标题:Python语法糖 - 修饰器的使用

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