Overview
This article explains the basic syntax for defining asynchronous functions using async def and the special return value called a “coroutine object.” Unlike regular functions (synchronous functions), a function defined with async def has a very important characteristic: the code inside is not executed just by calling the function.
Specifications (Input/Output)
- Input: Calling a function defined with
async def. - Output: An object of type
coroutine(not the result of the process). - Syntax:
async def function_name(arguments):
Basic Usage
To define an asynchronous function, add the async keyword before the function definition. When you call this function, it immediately returns a “coroutine object” as its return value.
import asyncio
# Defining an asynchronous function
async def my_coroutine():
print("This message will not be displayed just by calling the function.")
return "Finished"
# Calling the function
# The code inside the function is NOT executed yet!
obj = my_coroutine()
# Checking the type
print(type(obj)) # <class 'coroutine'>
Full Code
The following code demonstrates how a coroutine object is created and how to actually execute it to retrieve the result using asyncio.run.
import asyncio
# 1. Defining an asynchronous function (async def)
async def main_task(name):
print(f"[{name}] Asynchronous function started")
# Simulating an asynchronous process
await asyncio.sleep(1)
print(f"[{name}] Finished")
return f"Result of {name}"
# --- Execution Check ---
if __name__ == "__main__":
print("--- 1. Calling the function normally ---")
# Calling it like a regular function
coro = main_task("Test1")
# The return value is not the result, but a "coroutine object"
print(f"Return value type: {type(coro)}")
print(f"Object content: {coro}")
# Note: "Asynchronous function started" is not displayed yet.
# If you leave an unexecuted coroutine, you may get a RuntimeWarning.
coro.close() # Closing without executing
print("\n--- 2. Executing with the event loop ---")
# Execution begins only when passing the coroutine object to asyncio.run()
result = asyncio.run(main_task("Test2"))
print(f"Execution Result: {result}")
Customization Points
Coroutine Characteristics
The following table compares regular functions and asynchronous functions.
| Item | Regular Function (def) | Asynchronous Function (async def) |
| Keyword | def func(): | async def func(): |
| When Called | Executed immediately. | Returns a coroutine object without executing. |
| Execution Method | func() | await func() or asyncio.run(func()) |
| Return Value | Calculated result. | Calculated result (received after using await). |
Important Notes
RuntimeWarning
If you create a coroutine object (e.g., obj = main()) but end the program without using await or asyncio.run(), Python will issue a RuntimeWarning stating that the coroutine was never awaited.
await Restrictions
The await keyword, which is used to wait for the result of an asynchronous function, can only be used inside functions defined with async def. Using await inside a regular function will result in a syntax error.
Summary
async defcreates the “blueprint” of a coroutine.- Calling the function
()creates a “task waiting to be executed” (coroutine object). asyncio.run()orawaitactually performs the “execution.”
The fact that “calling” and “executing” are separate steps is the most significant feature of asynchronous processing in Python.
