Kai Zhang
Kai Zhang

Reputation: 175

Decorator to async function python

A simple decorate to calculate time a function takes to run:

import time
def decor(f):
  starttime=time.time()
  f()
  print("child functoin run time is ", (time.time()-starttime)*1000, "ms")
  return f

try to use it to decorate async functions:

async def sleep_and_print(seconds):
    print(f"starting async {seconds} sleep 😴")
    await asyncio.sleep(seconds)
    print(f"finished async {seconds} sleep ⏰")
    return seconds

@decor
async def main():
    # using arguments
    results = await asyncio.gather(sleep_and_print(3), sleep_and_print(6))
    print(results)

asyncio.run(main())

I got RuntimeWarning: coroutine 'main' was never awaited error If I change the decorator function to async and await, eg

async def decor(f):
  starttime=time.time()
  await f()
  print("child functoin run time is ", (time.time()-starttime)*1000, "ms")
  return f

asyncio.run(main()) failed with coroutine' object is not callable

Why main() becomes uncallable? Any suggestion on the work around?

Upvotes: 2

Views: 2861

Answers (1)

Andrej Kesely
Andrej Kesely

Reputation: 195428

Try to return async function from the decorator function:

import time
import asyncio


def decor(f):
    async def _fn():
        starttime = time.time()
        await f()
        print(
            "child function run time is ",
            (time.time() - starttime) * 1000,
            "ms",
        )

    return _fn


async def sleep_and_print(seconds):
    print(f"starting async {seconds} sleep 😴")
    await asyncio.sleep(seconds)
    print(f"finished async {seconds} sleep ⏰")
    return seconds


@decor
async def main():
    # using arguments
    results = await asyncio.gather(sleep_and_print(3), sleep_and_print(6))
    print(results)


asyncio.run(main())

Prints:

starting async 3 sleep 😴
starting async 6 sleep 😴
finished async 3 sleep ⏰
finished async 6 sleep ⏰
[3, 6]
child function run time is  6002.1820068359375 ms

Upvotes: 2

Related Questions