一日一技:装饰器如何装饰异步函数

简介: 一日一技:装饰器如何装饰异步函数

摄影:产品经理产品经理说她想吃肉。

在 Python 开发的工程中,我们常常使用装饰器来优化代码,例如一个打印日志的装饰器:

import requests
import datetime
def time_log(func):
    def wrap(*args, **kwargs):
        print(f'现在时间:{datetime.datetime.now()},程序开始运行')
        result = func(*args, **kwargs)
        print(f'现在时间:{datetime.datetime.now()},运行结束')
        return result
    return wrap
@time_log
def get(n):
    resp = requests.get(f'http://httpbin.org/delay/{n}').text
    print(resp)
get(3)

运行效果如下图所示:


但如果get是一个异步函数,这个装饰器就会出问题:

import pprint
import aiohttp
import datetime
import asyncio
def time_log(func):
    def wrap(*args, **kwargs):
        print(f'现在时间:{datetime.datetime.now()},程序开始运行')
        result = func(*args, **kwargs)
        print(f'现在时间:{datetime.datetime.now()},运行结束')
        return result
    return wrap
@time_log
asyncdef get(n):
    asyncwith aiohttp.ClientSession() as client:
        resp = await client.get(f'http://httpbin.org/delay/{n}')
        result = await resp.json()
    pprint.pprint(result, indent=2)
asyncio.run(get(3))

运行效果如下图所示:

可以看到,print(f'现在时间:{datetime.datetime.now()},程序开始运行')print(f'现在时间:{datetime.datetime.now()},运行结束')几乎同时被打印出来,然后才是请求网络。这并不是我们需要实现的效果。我们想要的是先打印前一行,然后请求网络,再打印后一行。

为了解决这个问题,我们需要把time_log装饰器中的wrap也定义成异步函数:

def time_log(func):
    asyncdef wrap(*args, **kwargs):
        print(f'现在时间:{datetime.datetime.now()},程序开始运行')
        result = await func(*args, **kwargs)
        print(f'现在时间:{datetime.datetime.now()},运行结束')
        return result
    return wrap

同时await func(*args, **kwargs)。这样就能保证代码的执行顺序:

但需要注意的是,装饰器本身是一个同步函数,不需要使用async def来定义。只有里面的闭包需要定义为异步函数。

目录
相关文章
|
8月前
|
数据安全/隐私保护 Python
Python中装饰器、回调函数、闭包、派生的区别与应用详解
Python中装饰器、回调函数、闭包、派生的区别与应用详解
71 0
|
1月前
|
JavaScript
03_装饰器
03_装饰器
50 1
|
1月前
22_自定义装饰器
22_自定义装饰器
83 0
|
10月前
|
JavaScript 前端开发 编译器
StencilJs 学习之组件装饰器
Stencil 是一个生成 Web Components(更确切地说,是自定义元素)的编译器。Stencil 将最流行的框架的最佳概念结合到一个简单的构建时工具中。 现在让我们一起学习其中的装饰器部分。
71 0
|
1月前
|
数据安全/隐私保护 Python
解释装饰器(decorator)的功能和用法。
解释装饰器(decorator)的功能和用法。
|
7月前
函数修饰器的理解
函数修饰器的理解
26 0
|
10月前
|
Java
闭包,类装饰lianx
当一个函数的返回值是另外一个函数,而返回的那个函数如果调用了其父函数内部的变量,且返回的这个函数在外执行就产生了闭包.闭包是一个环境,具体指的就是外部函数–高阶函数。 闭包有3个特性: ①函数嵌套函数 ②函数内部可以引用函数外部的参数和变量 ③参数和变量不会被垃圾回收机制回收
32 0
|
11月前
|
Python
python装饰器中的4种类型(函数装饰函数、函数装饰类、类装饰函数、类装饰类)
python装饰器中的4种类型(函数装饰函数、函数装饰类、类装饰函数、类装饰类)
95 0
|
JSON 数据格式
装饰器的实际应用
使用装饰器模式改造slf4j打印json格式日志
709 0
装饰器的实际应用