You cannot define an async lambda in Python at the time of writing, at least not via the “async lambda” syntax.
Nevertheless, there are a number of workarounds we can use to simulate an asynchronous lambda in Python, including defining an anonymous coroutine via an async generator.
In this tutorial, you will discover asynchronous lambdas in Python.
Let’s get started.
What is a Lambda in Python
A lambda in Python is a function without a name and with one expression.
A Python lambda is also called an anonymous function.
lambda: An anonymous inline function consisting of a single expression which is evaluated when the function is called.
— Python Glossary
The Python syntax for creating a lambda is the “lambda” keyword followed by any arguments, then a colon “:” followed by the expression to execute.
For example:
1 |
lambda [parameters]: expression |
Perhaps the most common lambda use case is in specifying how to sort a list.
The sort() method on the list takes a function via the “key” argument that takes a list item and returns the property by which to sort the list item.
It is common, almost universal to specify a lambda for the key function.
For example:
1 2 3 |
... # sort a list and use a lambda mylist.sort(key=lambda x:x[1]) |
Run loops using all CPUs, download your FREE book to learn how.
Lambdas Are Useful
Lambdas are very useful in Python, they are used all over the place.
Some reasons for the wide use of lambdas include:
- Conciseness: Lambda functions allow you to define small, simple functions in a single line of code. They are particularly handy for short, one-off operations where defining a full function using def would be overkill.
- Readability: For straightforward operations, lambda functions can make code more readable by keeping the function logic closely associated with the operation being performed. This can reduce cognitive load when reading the code.
- Inline Usage: You can use lambda functions inline, without needing to give them a name or define them elsewhere in the code. This is especially useful for quick calculations or transformations within a larger expression.
- Anonymous Callbacks: Lambda functions are often used as anonymous callbacks in event-driven programming, where you need a simple function to execute in response to an event without creating a named function.
- Reduced Code Bloat: In situations where you have many small, utility-like functions, using lambda can help reduce code bloat and make the codebase more maintainable.
Generally, we we want an async lambda, we also seek to achieve these properties.
Now that we know what lambdas are and why they are useful, let’s consider the need for asynchronous lambdas.
What Is An Async Lambda?
Just as a lambda is an anonymous function, e.g. a function with no name and one expression, an async lambda would be an anonymous coroutine.
- Async Lambda: An anonymous coroutine with no name and one expression.
Python does not support async lambdas (at the time of writing). They were mentioned in the PEP that introduced the async/await syntax, for example:
Async lambda functions: Syntax for asynchronous lambda functions could be provided, but this construct is outside of the scope of this PEP.
— PEP 492 – Coroutines with async and await syntax
If Python did support async lambdas, perhaps an async lambda would be defined using an “async lambda” expression, for example:
1 |
async lambda [parameters]: expression |
An async lambda would have the properties of a coroutine.
It would be able to await other coroutines and tasks, e.g. use the await expression.
For example:
1 |
async lambda : await asyncio.sleep(1) |
It could then be passed around as an argument, such as to another coroutine to be awaited.
For example:
1 2 3 |
... # await some other coroutine that takes an awaitable await somefunction(target=async lambda : await asyncio.sleep(1)) |
As mentioned, Python does not support this syntax for async lambdas at the time of writing.
It has been requested though, for example:
- Asynchronous lambda syntax
- Add support for async/await in the lambda expression
- Add support for async/await in the lambda expression
The general consensus from the experts and core developers is that there is no strong need for an async lambda.
For example:
I’ve thought about this idea before. And I came to the conclusion that in the simplest cases you can use a simple synchronous lambda returning an awaitable, and in more complex cases it is better to use a named internal function. Each async and await increase the length of the line, therefore the use of async lambda will not help with readability too much.
— Serhiy Storchaka, CPython core developer.
Instead of using an async lambda, we need to consider workarounds.
Free Python Asyncio Course
Download your FREE Asyncio PDF cheat sheet and get BONUS access to my free 7-day crash course on the Asyncio API.
Discover how to use the Python asyncio module including how to define, create, and run new coroutines and how to use non-blocking I/O.
Workarounds for Async Lambda
We do not have access to async lambdas in Python, yet.
Therefore, we have to develop a workaround.
Some suggested workarounds include:
- Define a new coroutine.
- Call a function instead of awaiting a coroutine.
- Use asyncio.run() if outside of a coroutine.
- Use a wrapper function.
- Use the asynchronous generator hack.
These workarounds cover most use cases, if you think I missed one, let me know in the comments below.
Let’s take a closer look at each in turn.
1. Define a New Coroutine
The default solution is to define a new coroutine that can be awaited.
We want to avoid this when using a lambda, so we have more compact code. If we let go of this desire and define a coroutine, we can get on with things.
For example, consider the use case of passing an async lambda as an argument to a coroutine:
1 2 3 |
... # await some other coroutine that takes an awaitable await somefunction(target=async lambda : await asyncio.sleep(1)) |
We could define a new coroutine to do this task and pass an instance of the coroutine directly.
For example:
1 2 3 4 5 6 7 |
# new coroutine async def task(): await asyncio.sleep(1) ... # await some other coroutine that takes an awaitable await somefunction(target=task()) |
2. Define and Call a Function
Another solution is to simply define a function to perform the task of the async lambda.
For example, consider the case where we want to use an async lambda when sorting a list.
For example:
1 2 3 4 5 6 7 |
# helper for getting the value from a tuple async def util(item): return item[1] ... # sort the list mylist.sort(key=lambda x : await util(x)) |
We define util() as a coroutine because we want async functions all the way down in our asyncio program.
The solution is to redefine util() as a regular Python function.
We can then use it as a regular lambda, no async required.
For example:
1 2 3 4 5 6 7 |
# helper for getting the value from a tuple def util(item): return item[1] ... # sort the list mylist.sort(key=lambda x : util(x)) |
3. Call With asyncio.run() If Outside of Asyncio
We may want to use an async lambda in regular Python, outside of an asyncio program.
This is likely because we are using some third-party library that has an API that expects awaitables as arguments or callbacks or similar.
Generally, I’d recommend developing your program as an asyncio program, rather than trying to hack in pockets of asyncio into your regular non-asyncio program.
Nevertheless, you can execute ad hoc coroutines in your program using the asyncio.run() function.
This will start an asyncio event loop and execute whatever coroutine you need to be executed.
For example, you may want a lambda to get a return value from a coroutine given an argument.
1 2 |
... value = async lambda : await task(100) |
We can execute the coroutine directly to get the result with asyncio.run().
For example:
1 2 3 4 5 6 7 8 9 10 |
# coroutine for doing a thing async def task(arg): # some awaiting await asyncio.sleep(10) # some return value return 100 * arg ... # execute coroutine and get return value value = asyncio.run(task(100)) |
You can learn more about executing one-off coroutines in the tutorial:
4. Use a Wrapper Coroutine
We may have a use case where we have a function that performs a required task, but an API requires a coroutine or awaitable.
In this case, we might just want to use an async lambda to call the function for us.
For example:
1 2 3 |
... # get the thing we need by calling python function value = await async lambda : util(item) |
In this case, we want to dress up a function to look like a coroutine.
We can achieve the same effect using a wrapper coroutine.
For example, we can define a wrapper coroutine that calls a target function.
1 2 3 4 |
# wrapper coroutine async def wrapper(target, *args, **kwds): # call the target return target(*args, **kwds) |
We can then await the wrapper and instruct the wrapper to call the target function for us.
For example:
1 2 3 |
... # get the thing we need value = await wrapper(util, item) |
A variation on this may be a target function that takes the name of a coroutine rather than a coroutine object.
It will then create and await the coroutine object.
For example:
1 2 3 |
... # await some other coroutine that takes an awaitable await somefunction(target=async lambda : util) |
We can define a wrapper function that returns a coroutine function that will call the target function for us when called.
For example:
1 2 3 4 5 6 7 8 |
# wrapper function def wrapper(target, *args, **kwds): # wrapper coroutine async def wrapped(): # call the target function return target(*args, **kwds) # return the coroutine return wrapped |
We can then pass the wrapper to the function.
1 2 3 |
... # await some other coroutine that takes an awaitable await somefunction(target=wrapper(util)) |
The somefunction() coroutine can then create and await the provided target.
For example, it might look like:
1 2 3 4 |
# some function that takes a target coroutine function async def somefunction(target): # ... await target() |
5. Use an Asynchronous Generator Hack
We can simulate an anonymous asynchronous function in Python using an asynchronous generator.
I call this the “asynchronous generator hack”.
I take no credit for this, it is based on an answer by MisterMiyagi aka Max Fischer on StackOverflow. All credit to him.
This is helpful in the case where we need an async function (e.g. awaitable, coroutines, task, etc.) and do not want to define one, instead, we want to use an async lambda to do a thing, like await something.
For example, a target coroutine that takes a coroutine object to be awaited for some purpose.
1 2 3 |
... # await some other coroutine that takes an awaitable await somefunction(target=async lambda : await asyncio.sleep(1)) |
The asynchronous generator hack works by defining the smallest possible asynchronous generator that just executes the one line we want to be executed.
For example:
1 2 3 |
... # define an anonymous async function var = (await asyncio.sleep(1) for _ in '_').__anext__() |
Awaiting this thing will suspend the caller and execute the inner statement.
For example:
1 2 3 |
... # execute the statement await var |
Or in one line:
1 2 3 |
... # define and await an anonymous async function await (await asyncio.sleep(1) for _ in '_').__anext__() |
It is the same as defining a coroutine, creating it, and then awaiting it.
1 2 3 4 5 6 |
# define a named coroutine async def mycoro(): await asyncio.sleep(1) # await the coroutine await mycoro() |
Which could be squashed to two “lines”:
1 2 3 4 |
# define a named coroutine async def mycoro(): await asyncio.sleep(1) # await the coroutine await mycoro() |
Now, recall our use case.
The coroutine somefunction() takes an argument “target” that is an awaitable.
The updated version using this hack is as follows:
1 2 3 |
... # await some other coroutine that takes an awaitable await somefunction(target=(await asyncio.sleep(1) for _ in '_').__anext__()) |
Cool.
Learn more about the description of the hack as proposed by “MisterMiyagi” aka Max Fischer here.
Learn more about async generators here:
Now that we know how to work around async lambdas, let’s look at some worked examples.
NOTE: To be crystal clear, the examples below are not intended to motivate the addition of “async lambda” to Python, rather they are exploring contrived use cases we may encounter and thinking we need an async lambda and to show an alternative solution that could be used.
Overwhelmed by the python concurrency APIs?
Find relief, download my FREE Python Concurrency Mind Maps
Example of Lambda Cannot Await
Before we look at workarounds for async lambda, we can explore the case where we cannot use an await expression within a regular synchronous lambda.
This means that we cannot define regular lambdas that act like asynchronous functions, aka coroutines.
In this case, we will sort a list of tuples via the sort() method on the list. We have a coroutine defined that we want to call to pull the key out of each item in the list so that we can sort by it.
1 2 3 |
# helper for getting the value from a tuple async def util(item): return item[1] |
We then attempt to await this coroutine to get the key for each item when sorting the list.
1 2 3 |
... # sort the list mylist.sort(key=lambda x : await util(x)) |
The expectation is that the use of an await expression outside of a coroutine, such as within the sort() method, will result in a SyntaxError.
This is contrived but demonstrates that a lambda cannot use an await expression.
It provides a loose context for exploring many cases where we could use an async lambda.
Tying this together, the complete example is listed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# SuperFastPython.com # example of cannot use await in lambda import asyncio # helper for getting the value from a tuple async def util(item): return item[1] # main coroutine async def main(): # create list of tuples mylist = [('red', 2), ('green', 1), ('blue', 3)] # report the list print(mylist) # sort the list mylist.sort(key=lambda x : await util(x)) # report the sorted list print(mylist) # start the event loop asyncio.run(main()) |
The example does not run, as we expected.
Instead, it immediately fails with a SyntaxError that an await cannot be used outside of a coroutine.
1 |
SyntaxError: 'await' outside async function |
Next, let’s start exploring some workarounds for the need for an async lambda.
Example of Defining a Named Coroutine
We can explore a workaround to an asyncio lambda by defining a named coroutine.
In this case, the program will define a list of tuples then traverse the list and await coroutine to retrieve the correct value from each tuple that is then reported.
Let’s pretend that the tuple is a structure that requires awaiting in order to retrieve an item. Bear with me.
We would like to use an async lambda to await an expression that will retrieve a value from the tuple each iteration.
For example:
1 2 3 4 5 6 |
... for item in mylist: # get the thing we need value = await async lambda item : item[1] # report the value print(value) |
Instead, we can define a named coroutine that does this work for us.
1 2 3 |
# helper for getting the value from a tuple async def util(item): return item[1] |
We can then await this coroutine directly which will access the required value from the tuple.
1 2 3 4 5 6 |
... for item in mylist: # get the thing we need value = await util(item) # report the value print(value) |
Tying this together, the complete example is listed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# SuperFastPython.com # example of defining a named coroutine import asyncio # helper for getting the value from a tuple async def util(item): return item[1] # main coroutine async def main(): # create list of tuples mylist = [('red', 2), ('green', 1), ('blue', 3)] for item in mylist: # get the thing we need value = await util(item) # report the value print(value) # start the event loop asyncio.run(main()) |
Running the example first starts the event loop and runs the main() coroutine.
The main() coroutine defines the list of tuples.
It then traverses the list of tuples.
For each tuple, it suspends the main() coroutine and awaits the util() coroutine with an item argument.
The util() coroutine runs and retrieves the correct value from the tuple.
The main() coroutine resumes and reports the retrieved value, and the loop repeats.
This highlights how we can develop a named coroutine as a workaround, instead of using an anonymous async lambda.
1 2 3 |
2 1 3 |
Example of Function Call Instead of Await Coroutine
We can explore the case of using a function call instead of using an async lambda.
In this case, the main program defines a list of tuples. It then seeks to sort the list via the sort() method and use a given item as a key.
We have a coroutine named util() that is used to define which item to retrieve from the tuple that is to be used to sort the list.
For example:
1 2 3 4 |
... # helper for getting the value from a tuple async def util(item): return item[1] |
We would like to use an async lambda to await this coroutine when sorting the list.
For example:
1 2 3 |
... # sort the list mylist.sort(key=async lambda x : await util(x)) |
This may happen if our program is an asyncio program and we are using coroutines for everything.
Instead, in this case, because the target function does nothing coroutine-specific, we can convert the util() coroutine to a regular Python function.
For example:
1 2 3 |
# helper for getting the value from a tuple def util(item): return item[1] |
And then use it within the regular lambda in the sort() function.
For example:
1 2 3 |
... # sort the list mylist.sort(key=lambda x : util(x)) |
Granted, this could be simpler in this case:
1 2 3 |
... # sort the list mylist.sort(key=lambda x : x[1]) |
But let’s pretend that util() is doing more sophisticated things.
Tying this together, the complete example is listed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# SuperFastPython.com # example of calling a target function instead of awaiting a coroutine import asyncio # helper for getting the value from a tuple def util(item): return item[1] # main coroutine async def main(): # create list of tuples mylist = [('red', 2), ('green', 1), ('blue', 3)] # report the list print(mylist) # sort the list mylist.sort(key=lambda x : util(x)) # report the sorted list print(mylist) # start the event loop asyncio.run(main()) |
Running the example first starts the event loop and runs the main() coroutine.
The main() coroutine defines the list of tuples and then reports the contents of the list.
It then sorts the list using a regular lambda that calls our custom util() function for each iteration to get the second item in the tuple as the key by which to sort the list.
The main() coroutine then reports the contents of the list of tuples again, showing they were correctly sorted by the second value in the tuple.
This highlights how we can convert a coroutine into a Python function to workaround the need for an async lambda.
1 2 |
[('red', 2), ('green', 1), ('blue', 3)] [('green', 1), ('red', 2), ('blue', 3)] |
Example of Calling asyncio.run() Outside of Asyncio
We can explore the case of running a one-off coroutine rather than converting everything to an asyncio program.
In this case, we have a regular Python program that creates a loop of tuples, then traverses the loop and retrieves a value from each tuple, and reports it.
We have a coroutine that needs to be used to retrieve a value from each tuple.
1 2 3 |
# helper for getting the value from a tuple async def util(item): return item[1] |
We would like to use an async lambda to get the value from each tuple.
For example:
1 2 3 4 5 6 |
... for item in mylist: # get the thing we need value = await async lambda item : util(item) # report the value print(value) |
This would fail with a syntax error because we are using an await outside of a coroutine. It is not even a good use case for an async lambda.
Nevertheless, we can overcome this problem by creating an asyncio event loop and executing the coroutine as a one-off for each iteration.
This can be achieved via the asyncio.run() function.
For example:
1 2 3 4 5 6 |
... for item in mylist: # get the thing we need value = asyncio.run(util(item)) # report the value print(value) |
Tying this together, the complete example is listed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# SuperFastPython.com # example of executing coroutines outside of asyncio import asyncio # helper for getting the value from a tuple async def util(item): return item[1] # main coroutine def main(): # create list of tuples mylist = [('red', 2), ('green', 1), ('blue', 3)] for item in mylist: # get the thing we need value = asyncio.run(util(item)) # report the value print(value) # start the program main() |
Running the example first executes the main() function.
The main() function runs and creates a list of tuples.
It then traverses the list of tuples.
For each tuple, it creates an asyncio event loop and executes the util() coroutine with a tuple argument.
The event loop runs and executes the util() coroutine.
The util() coroutine runs and retrieves the desired value from the provided tuple, which is returned.
The event loop is terminated and the returned value is assigned and reported.
This highlights how we can spin up an asyncio event loop to execute one-off coroutines instead of using an async lambda.
1 2 3 |
2 1 3 |
Example of Wrapper Coroutine For Target Function
We can explore the case of using a wrapper coroutine that calls a target function instead of using an async lambda.
In this case, we will create a list of tuples, then enumerate the list and retrieve one value from each tuple that is reported.
We have a defined Python function named util() that can retrieve the correct value from each tuple.
1 2 3 |
# helper for getting the value from a tuple def util(item): return item[1] |
Nevertheless, the main program is required to await a coroutine to get a value from each tuple.
We would like to use an async lambda that in turn calls the target function.
For example:
1 2 3 4 5 6 |
... for item in mylist: # get the thing we need value = await async lambda item : util(item) # report the value print(value) |
This can be achieved using a generic wrapper coroutine.
The wrapper coroutine takes the name of a Python function to execute and any arguments to the function.
When awaited, it will execute the target function and return the return value from the function.
The wrapper() coroutine implements this.
1 2 3 4 |
# wrapper coroutine async def wrapper(target, *args, **kwds): # call the target return target(*args, **kwds) |
We can then await the wrapper() coroutine in the loop of our main program and pass it the name of the target function “util” and the argument to the util() function.
For example:
1 2 3 4 5 6 |
... for item in mylist: # get the thing we need value = await wrapper(util, item) # report the value print(value) |
Tying this together, the complete example is listed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# SuperFastPython.com # example of wrapper coroutine for target function import asyncio # wrapper coroutine async def wrapper(target, *args, **kwds): # call the target return target(*args, **kwds) # helper for getting the value from a tuple def util(item): return item[1] # main coroutine async def main(): # create list of tuples mylist = [('red', 2), ('green', 1), ('blue', 3)] for item in mylist: # get the thing we need value = await wrapper(util, item) # report the value print(value) # start the event loop asyncio.run(main()) |
Running the example first starts the event loop and runs the main() coroutine.
The main() coroutine runs and creates a list of tuples.
It then enumerates the list of tuples.
In each iteration the main() coroutine suspends and awaits the wrapper() coroutine.
The wrapper() coroutine runs and calls the util() function and a tuple argument.
The util() function runs and retrieves one item from the tuple which is returned to the wrapper() coroutine and then back to the main() coroutine where it is reported.
This example highlights how we can use a wrapper coroutine to call a target function instead of using an async lambda.
1 2 3 |
2 1 3 |
Example of Wrapper Function That Returns Wrapper Coroutine
We can explore the case of using a wrapper function that returns a coroutine that can be created and awaited instead of using an async lambda.
In this case, the main program will create a list of tuples, then enumerate the list of tuples and create a given coroutine, and await it to retrieve a specific value from each tuple in the list, which is then reported.
We have a Python function named util() that can retrieve the correct value from each tuple.
1 2 3 |
# helper for getting the value from a tuple def util(item): return item[1] |
We would like to use an async lambda that can be created and awaited each iteration to call the target function.
For example, perhaps something like:
1 2 3 4 5 6 |
... for item in mylist: # get the thing we need value = await (async lambda item : util(item))() # report the value print(value) |
The syntax for defining and instantiating an anonymous coroutine is getting confused now. Anyway, bear with me.
Instead, we can use a wrapper Python function that takes the name of the target function and any arguments. It then defines an inner coroutine that calls the target function and returns the name of this coroutine.
This returned coroutine can then be instantiated and executed.
The wrapper() Python function implements this.
1 2 3 4 5 6 7 8 |
# wrapper function def wrapper(target, *args, **kwds): # wrapper coroutine async def wrapped(): # call the target function return target(*args, **kwds) # return the coroutine return wrapped |
We can then call the wrapper() function inline and pass it the name of the target function “util” and the argument to the function. This will return the name of a coroutine function that can be created and awaited.
For example:
1 2 3 4 5 6 |
... for item in mylist: # get the thing we need value = await wrapper(util, item)() # report the value print(value) |
Tying this together, the complete example is listed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# SuperFastPython.com # example of wrapper function that returns wrapper coroutine import asyncio # wrapper function def wrapper(target, *args, **kwds): # wrapper coroutine async def wrapped(): # call the target function return target(*args, **kwds) # return the coroutine return wrapped # helper for getting the value from a tuple def util(item): return item[1] # main coroutine async def main(): # create list of tuples mylist = [('red', 2), ('green', 1), ('blue', 3)] for item in mylist: # get the thing we need value = await wrapper(util, item)() # report the value print(value) # start the event loop asyncio.run(main()) |
Running the example first starts the event loop and runs the main() coroutine.
The main() coroutine runs and creates a list of tuples.
It then enumerates the list of tuples.
In each iteration, the main() coroutines suspends and awaits the coroutine instance of the return value from the wrapper() function.
The wrapper() function runs and calls define a coroutine that calls a target function and returns the name of the inner coroutine function.
The main() coroutine suspends and creates an instance of the wrapped() coroutine and awaits it.
The wrapped() coroutine runs and executes the util() function with an item argument.
The util() function runs and retrieves one item from the tuple which is returned to the wrapped() coroutine and then back to the main() coroutine where it is reported.
This example highlights how we can use a wrapper function to define a wrapped coroutine to call a target function that can be created when needed and awaited, instead of using an async lambda.
1 2 3 |
2 1 3 |
Example of Asynchronous Generator Hack
We can explore the use of the asynchronous generator hack to create an anonymous coroutine, instead of using an async lambda.
In this case, we are traversing a list of tuples and want to retrieve and report one item from each tuple.
We will pretend that we need a coroutine to await a task that will return the item and would like to use an async lambda.
For example:
1 2 3 4 5 6 |
... for item in mylist: # get the thing we need value = await async lambda item : await util(item) # report the value print(value) |
Granted, we could just await the target coroutine directly.
For example:
1 2 3 4 5 6 |
... for item in mylist: # get the thing we need value = await util(item) # report the value print(value) |
The example may be overly contrived.
Nevertheless, we can use the async generator hack to define an anonymous coroutine to await the target for us.
For example:
1 2 3 4 5 6 |
... for item in mylist: # get the thing we need value = await (await util(item) for _ in '_').__anext__() # report the value print(value) |
Tying this together, the complete example is listed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# SuperFastPython.com # example of async generator hack import asyncio # helper for getting the value from a tuple async def util(item): return item[1] # main coroutine async def main(): # create list of tuples mylist = [('red', 2), ('green', 1), ('blue', 3)] for item in mylist: # get the thing we need value = await (await util(item) for _ in '_').__anext__() # report the value print(value) # start the event loop asyncio.run(main()) |
Running the example first starts the event loop and runs the main() coroutine.
The main() coroutine runs and creates a list of tuples.
It then enumerates the list of tuples. Each iteration it awaits the anonymous coroutine to get the required data from each tuple, which is then reported.
The anonymous coroutine is awaited, suspending the caller and executing the async generator and yielding the first value. This suspends and awaits the target util() coroutine that returns the second value in the tuple.
This highlights how we can use the async generator hack to define and await anonymous coroutines to simulate an async lambda.
1 2 3 |
2 1 3 |
Further Reading
This section provides additional resources that you may find helpful.
Python Asyncio Books
- Python Asyncio Mastery, Jason Brownlee (my book!)
- Python Asyncio Jump-Start, Jason Brownlee.
- Python Asyncio Interview Questions, Jason Brownlee.
- Asyncio Module API Cheat Sheet
I also recommend the following books:
- Python Concurrency with asyncio, Matthew Fowler, 2022.
- Using Asyncio in Python, Caleb Hattingh, 2020.
- asyncio Recipes, Mohamed Mustapha Tahrioui, 2019.
Guides
APIs
- asyncio — Asynchronous I/O
- Asyncio Coroutines and Tasks
- Asyncio Streams
- Asyncio Subprocesses
- Asyncio Queues
- Asyncio Synchronization Primitives
References
Takeaways
You now know how to work around async lambdas in Python.
Did I make a mistake? See a typo?
I’m a simple humble human. Correct me, please!
Do you have any additional tips?
I’d love to hear about them!
Do you have any questions?
Ask your questions in the comments below and I will do my best to answer.
Photo by Aziz Acharki on Unsplash
Do you have any questions?