1. 程式人生 > 其它 >測試平臺系列(65) 非同步方法裝飾器

測試平臺系列(65) 非同步方法裝飾器

大家好~我是米洛


我在從0到1打造一個開源平臺, 也在編寫一套完整的介面測試平臺系列教程,希望大家能夠多多支援。



歡迎關注我的公眾號測試開發坑貨,獲取最新文章教程!

回顧

上一節我們完善了一整套測試用例執行的流程,這一節我們來講講async方法的裝飾器

在此之前,我們先來看下用於非同步方法的裝飾器。

日誌裝飾器

還記得我們之前編寫過的日誌裝飾器嗎?不記得的話也沒關係,咱們現滷一個。

import functools


def log(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print("正在執行方法: ", func.__name__)
        print("引數: ", *args, *[f"{k}={v} " for k, v in kwargs.items()])
        result = func(*args, **kwargs)
        print("執行結果: ", result)
        return result

    return wrapper


@log
def print_user(name, age, height=180):
    return f"hello, {name}. Age: {age}, Height: {height}"


if __name__ == "__main__":
    print_user("klose", 43, height=182)

我們編寫了一個print_user(列印使用者資訊)的方法,並給他加上了log裝飾器,這樣一旦這個方法執行了,我們就會輸出這些資料到日誌裡面。

因為這裡我沒有現成的日誌包,所以我用了print代替。輸入到日誌需要記錄什麼內容呢?

  • 呼叫了什麼方法

  • 方法的引數是什麼

  • 方法的返回值是什麼

    我們來看看輸出:

就是這麼個場景,普通的裝飾器實現如上。接著我們來思考一個問題,如果我們的方法是非同步的,在裝飾器不變的情況下,會是什麼輸出呢?

求豆麻袋。

我們來進行下簡單的改造。

async方法的裝飾器

@log
async def print_user(name, age, height=180):
    return f"hello, {name}. Age: {age}, Height: {height}"

只需要把print_user方法改為async,然後用asyncio.run執行print_user方法即可。來看下輸出:

@log
async def print_user(name, age, height=180):
    return f"hello, {name}. Age: {age}, Height: {height}"

if __name__ == "__main__":
    asyncio.run(print_user("klose", 43, height=182))

可以看到,執行結果變成了coroutine了,也就是說拿不到返回值了。

那麼接下來就進入我們的改造階段

,讓裝飾器也支援非同步方法。

查詢資料

通過google,我們發現asyncio有這樣一個方法: iscoroutinefunction

看名字就知道,是判斷一個function是不是coroutine,如果這招有用的話,那說明我們的問題能夠解決了。

def log(func):
    if asyncio.iscoroutinefunction(func):
        @functools.wraps(func)
        async def wrapper(*args, **kwargs):
            print("正在執行方法: ", func.__name__)
            print("引數: ", *args, *[f"{k}={v} " for k, v in kwargs.items()])
            result = await func(*args, **kwargs)
            print("執行結果: ", result)
            return result
    else:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print("正在執行方法: ", func.__name__)
            print("引數: ", *args, *[f"{k}={v} " for k, v in kwargs.items()])
            result = func(*args, **kwargs)
            print("執行結果: ", result)
            return result
    return wrapper

我們把程式碼改成這個樣子: 可以看到,裝飾器又和上一次講的一樣,進入了一個分水嶺,當iscoroutine成立的時候,形成了一個async的裝飾器,反之則是普通的裝飾器。

試試效果先

再試試把log放到普通方法上面:

程式碼冗餘

細心的朋友可能發現了,3個print的內容都是很重複的,但是ide並沒有提示你,但其實這幾塊內容是完全可以封裝起來的。

這大概就是順手為之,慢慢就形成了屎山程式碼吧~

所以核心方法是asyncio.iscoroutinefunction, 你學會了嗎?


今天的內容就介紹到這裡了,大家沒點關注的點個關注,點了關注的點個贊,點了讚的點個在看,點了在看的點個讚賞,點了讚賞的點個退出