一、背景

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可以传递函数的特性,将函数作为参数进行传递,实现的关键部分是使用函数的闭包来完成装饰的过程。在实现测试的时候使用原函数和装饰函数的调用进行结果判断即可。

posted on 2021-07-30 23:30  蔚蓝色の天空  阅读(480)  评论(0编辑  收藏  举报