zoukankan      html  css  js  c++  java
  • python中装饰器的使用

    一、背景

    python中最为重要的一个概念就是装饰器,这里记录一下原理和方法。从flask源码出发编写一个日志的装饰器。
    1.1 装饰器的类型

    • 函数式装饰器
    • 类装饰器

    二、装饰器原理与使用

    装饰器实际是将函数作为参数传入到另一个函数中,并且可以执行传入的函数。这使得装饰器能够将很多统一流程或者是重复的内容集成在一起。
    2.1 flask中的装饰器
    flask的路由就是使用装饰器完成的,这里查看一下它的源码

    """
    使用例子
    @app.route('/')
    def index():
    	return 'Hello World'
    	
    # 源码:
    """ 前面是整个Flask Object"""
    def route(self, rule, **options):
        def decorator(f):
            endpoint = options.pop('endpoint', None)
            # 将其注册到视图中
            self.add_url_rule(rule, endpoint, f, **options)
            return f
        return decorator
    """
    
    1.route部分:
        其中route中rule是接收路由参数,因此可以知道,通过使用装饰器的语法糖@装饰名在里面传递参数,因此我们可以通过这个方法去记录日志的等级。
    2.decorator部分:
    	将获取到的参数传递给add_url_rule添加规则,其中rule是路由,endpoint是默认的视图,f是编写传进来的函数,也就是自己编写路由完成的功能。因此使用闭包的形式将整个装饰器执行。
    
    总结:
    	根据上述的源码可以知道使用闭包完成了整个装饰过程,并且装饰器执行的时候就会执行闭包的函数,因此在闭包中直接执行f()也是可以完成函数的执行。
    

    2.2 实现一个日志管理
    根据上述的总结按照以下的步骤就可以实现一个日志装饰器

    1.编写日志的抽象函数
    2.使用装饰器通过参数传递,确定日志类型
    3.执行被装饰的函数,同时反序列化。
    

    代码如下:

    def log(path, **kwargs):
        """
        :param path:日志的路径
        :param kwargs: 其余的日志参数
        :return:
        """
    
        def decorator(f):
            statue = kwargs.pop("statue", "logging")  # 默认的日志等级是logging
            # 输出代替反序列化
            print("已存储函数%s,等级:%s" % (f.__name__, statue))
            print("函数参数个数{0},函数返回值{1}".format(f.__code__.co_argcount, f.__defaults__))
            print("函数参数参数名{0}".format(f.__code__.co_varnames))
            print(f(10, 9))
            return f
    
        return decorator
    
    @log("/one.txt")
    def one_record(a, b):
        """
        这个函数执行的内容
        :param b: int
        :param a: int
        :return: sum
        """
        return a + b
    
    @log("/two.txt", statue="danger")
    def two_record(a, b):
        """
        :param a: int
        :param b: int
        :return: sub
        """
        return abs((a - b))
    

    结果

    输出结果:
    已存储函数one_record,等级:logging
    函数参数个数2,函数返回值None
    函数参数参数名('a', 'b')
    19
    已存储函数two_record,等级:danger
    函数参数个数2,函数返回值None
    函数参数参数名('a', 'b')
    1
    

    2.3 多个装饰器的使用
    使用多个装饰器的时候,只需要继续在前面添加语法糖就可,实例如下:

    # 新加一个带装饰函数
    def path(**kwargs):
        def warp(f):
            print(f.__name__)
            return f
    
        return warp
    
    # 执行顺序是log-->path,相当于one_record=path(log(one_record))
    @path()
    @log("/one.txt")
    def one_record(a, b):
        """
        这个函数执行的内容
        :param b: int
        :param a: int
        :return: sum
        """
        return a + b
    

    2.4 装饰器的测试
    为了检验结果,需要写一些测试用例证明装饰器的正确性,下面介绍一下编写的过程。

    # 这就是正常调函数的结果
    fun_res = one_record(1, 3)
    # 这个是装饰器调用的结果
    # log是装饰的函数,one_record是被装饰的函数, (1, 3)表示函数中的值,因为log中的闭包需要一个函数类型,因此先将函数传递进去,再将参数传递进去。
    dec_rest = log("12")(one_record)(1, 3)
    # 进行真假值的判断。
    print(fun_res == dec_rest)
    

    三、总结

    装饰器在python中是一个比较重要的内容,其核心思想就是利用python可以传递函数的特性,将函数作为参数进行传递,实现的关键部分是使用函数的闭包来完成装饰的过程。在实现测试的时候使用原函数和装饰函数的调用进行结果判断即可。

  • 相关阅读:
    Difference between 2>&-, 2>/dev/null, |&, &>/dev/null and >/dev/null 2>&1
    (OK)(OK) docker-(centos-quagga-ospf-mdr)--NS3--MANET
    How to Interactively Create a Docker Container
    (OK)(www.nrl.navy.mil) OSPF MANET Designated Routers (OSPF-MDR) Implementation
    docker-batman
    (OK)(OK) NS3
    quagga-mtr——Multi-Topology Routing support for quagga routing suite
    (OK)(OK) seem-tools-CLI-manual.sh
    (OK)(OK) seem-tools-CLI-semi-auto.sh
    (OK)(OK) manet-seem-template.cc
  • 原文地址:https://www.cnblogs.com/future-dream/p/15082954.html
Copyright © 2011-2022 走看看