了解inspect python中的coroutine和iscoroutinefunction

问题描述 投票:0回答:1

给定一个具有同步方法但在另一个类中调用异步方法的类。当我尝试在同步类中调用同步方法时,我仍然得到协程从未等待过。以下是示例脚本

from time import perf_counter as timer
from functools import wraps
from typing import Union
from inspect import iscoroutinefunction


from dscommonutil.logger.basic import Logger

log = Logger("abc", ".")
log.start()


def timeit(task: str, logger: Union[Logger, str] = "log"):
    def _timeit(func):
        nonlocal logger
        if isinstance(logger, Logger):
            obj_check = False
        elif isinstance(logger, str):
            obj_check = True
        else:
            raise ValueError(
                f"{logger} needs to be a valid logging object or"
                " an attribute of args[0] parameter."
            )

        @wraps(func)
        async def wrapper(*args, **kwargs):
            nonlocal logger
            start_time = timer()
            if obj_check and (
                isinstance(args[0], object) and getattr(args[0], logger, False)
            ):
                logger = getattr(args[0], logger)

            if iscoroutinefunction(func):
                value = await func(*args, **kwargs)
            else:
                value = func(*args, **kwargs)
            logger.info_metric(
                    f"Time elapsed in {task}",
                    round(timer() - start_time, 2)
                )
            return value
        return wrapper
    return _timeit


class Async:
    def __init__(self):
        self.log = log

    @timeit(task="running sync function")
    def sync(self, arg):
        self.log.info_print("Inside Synchronous Function")
        return arg
    
    @timeit(task="running async function")
    async def caller(self, arg):
        self.log.info_print("Inside Asynchronous Function")
        value = await self.sync(arg)
        return value


class Client:
    def __init__(self):
        self.log = log

    @timeit(task="random func")
    def func(self):
        self.log.info_print("Inside func from client")
        return "Hello"


    def main(self):
        print(self.func())

        a = Async()
        return a.caller("abc")



if __name__ == '__main__':
    import asyncio
    c = Client()
    asyncio.run(c.main())

注意: dscommonutil 是一些内部开发的日志记录库,这是纯同步的。

问题主要是在拨打

self.func()
时出现,显示为
RuntimeWarning: coroutine 'Client.func' was never awaited

任何人都可以帮助理解这里调用函数的适当方法是什么,以及如何在不使用

await
的情况下进行同步调用?

如果我简单地添加代码就可以工作

value = await self.func()
print(value)

我想更多地了解 Python 的异步功能,据我所知,这不应该被

inspect.iscoroutinefunction
检测为协程,但不知何故它确实这样做了。

python-3.x asynchronous async-await python-asyncio
1个回答
0
投票

我尝试运行你的代码,问题似乎出在

async def wrapper(*args, **kwargs)
。由于它是一个异步装饰器,因此它希望您等待它,即使它包装了同步方法。您可能会考虑使包装器同步。这个例子可能对你有帮助。

def timeit(func):
    def _timeit(func):
        nonlocal logger
        if isinstance(logger, Logger):
            obj_check = False
        elif isinstance(logger, str):
            obj_check = True
        else:
            raise ValueError(
                f"{logger} needs to be a valid logging object or"
                " an attribute of args[0] parameter."
            )
     @functools.wraps(func)
     def wrapper(*args, **kwargs):
        nonlocal logger
        start_time = timer()
        _timeit(func)

        if obj_check and (
           isinstance(args[0], object) and getattr(args[0], logger, False)
        ):
        logger = getattr(args[0], logger)

       if not asyncio.iscoroutinefunction(func):
           return func(*args, **kwargs)
       else:
           async def tmp():
                 return (await func(*args, **kwargs))
           return tmp()
   return wrapper
© www.soinside.com 2019 - 2024. All rights reserved.