Python装饰器 + tornado实现装饰器捕获异常

1 篇文章 0 订阅
1 篇文章 0 订阅

 

闭包的概念(官方)

在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。

 

 

官方的解释有点迷糊

通俗说法是

定义两层函数 外函数是内函数的返回值 内函数引用外函数的变量

也就是说如果内函数不引用外函数 那就是个普通函数

引用场景

我这几天也一直在想应用场景(除装饰器外的)

看到最多的例子类似于这样

def func(a, b):
    def result(x):
        return a * x - b

    return result


result = func(2, 3)
print(result(5))

初始化的时候是外部函数 传参a,b

执行的时候运行的是内部函数

我目前感觉最大的用处就是装饰器吧

 

装饰器的基本用法

假如我需要捕获异常

我们从很简单的装饰一步一步实现出来最复杂的三层带参数的装饰器

先写一个最简单的装饰器捕获异常的

def log_decorator(fun):
    def wrapper():
        try:
            print("进入wap")
            fun()
        except Exception as e:
            print("异常:{}".format(e))
    return wrapper


@log_decorator
def error_test():
    print(5/0)



# log_decorator(error_test)

error_test()

可以看到我们只是把被装饰的函数 放到了一个新的函数内做了处理@ 是语法糖 

其实就是执行了 类似于我注释这行

也可以清晰的看见装饰器所捕获的不能/0异常

进入wap
异常:error_test() missing 1 required positional argument: 'print_str'

 

可以看到说明我们先进入了装饰器的内函数在打印了 进入wap后 才执行的代码 

那如何给他传参是个问题

假如需求是如何传参 num 用num除以0

 

@log_decorator
def error_test(num):
    print(num)
    print(num/0)

这时候就报异常处理有问题

异常:error_test() missing 1 required positional argument: 'num'

说缺少一个参数num

那我们可以换一步思考 解包 就是我不管你传什么参数进去 我都能让被装饰的函数完美包容

def log_decorator(fun):
    def wrapper(*args, **kwargs):
        try:
            print("进入wap")
            fun(*args, **kwargs)
        except Exception as e:
            print("异常:{}".format(e))
    return wrapper


@log_decorator
def error_test(num):
    print(num)
    print(num/0)



# log_decorator(error_test)

error_test(5)

此时在做修改 就会发现 依旧是我们5/0的异常说明传参的问题解决了

 

那么好了 在实战当中其实我们的需求比这个更明显

1在tornado项目中 定义捕获异常装饰器  

2 装饰器 要可以自定义返回内容  

3 出现错误时记录错误

4 要记录 这是哪个函数 

 

# 日志装饰器
def except_decorator(api_name,result_error='服务器异常'):
    def wrapper(func):
        @functools.wraps(func)
        def inner_wrapper(self, *args, **kwargs):
            try:
                return func(self, *args, **kwargs)
            except Exception as e:
                Log.error("{}接口出现异常:{}".format(api_name, e))
                return self.write({"code": -1, "msg": result_error})

        return inner_wrapper

    return wrapper

 

之前说过装饰器是闭包

闭包如果不引用外函数变量就是普通函数

由此可以推论出 那第一层的函数 我接受两个参数 就是我自定义的 错误结果 和 接口名称

然后里面这两层函数才是我的装饰器

而self 你必须要传 因为需要调到self的本身 

 

这个最外层的函数其实可以不要api_name的  其实可以 func__name___来记录的

至于@functools.wraps 是将原有的被装饰的名字返回给你

可以单独搜搜这个这个方法的用处 如果不懂

在tornado上可能没啥问题 不用这包也没事 但是在flask上会出现循环导入的错误

因为flask 本身的路由也是装饰器 并且以 是 api_name: function 的方式存储

如果说你没有返回给该函数的原有名字  flask将找不到所以会报错

至于为什么要传self 是因为tornado的返回方法是 self.write()

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值