Vic
Vic

Reputation: 8991

How to have conditional logic within asyncio.gather?

I want to run an async function conditionally, something like this:

one, two, three = await asyncio.gather(
    some_async_method1(),
    some_async_method2() if some_condition else None, # None doesn't work here
    some_async_method3()
)

I expect two to be None when some_condition is False. How to make this work?

Upvotes: 2

Views: 787

Answers (3)

Mahesh Malekar
Mahesh Malekar

Reputation: 11

Instead of None you can use asyncio.sleep(0) -

one, two, three = await asyncio.gather(
    some_async_method1(),
    some_async_method2() if some_condition else asyncio.sleep(0),
    some_async_method3()
)

Upvotes: 1

jsbueno
jsbueno

Reputation: 110476

You can pass the expansion of a generator expression as parameters to gather, and use the filtering component of it to apply your condition:

one, two, three = await asyncio.gather(*(
       method() for method in (
            some_async_method1, some_async_method2, some_async_method3
        ) if method != some_async_method2 or some_condition
    ) 
)

What is being done here: the positional arguments to gather are being passed as the inplace expansion of the results of the generator - (the *( part after openning the ( to call asyncio.gather).

This syntax is peculiar to Python: it allows a for and an if in an expression: the first part os the expression is only executed, for each item in the for if the condition in the if is true. So, when "some_condition" is False, it does not generate an item for the the second function at all.

Check https://peps.python.org/pep-0289/

If generator expressions won't be easier for you in the real code (it should because it makes easy to evaluate conditions for all functions), the expansion of parameters can help in this particular example: you can expand inplace a list with the conditional function, or an empty list:

one, two, three = await asyncio.gather(
    some_async_method1(),
    *([some_async_method2()] if some_condition else []), # the condition will create either a one-item-list with the method2, or an empty-list: both will be expanded as positional parameters in this point of the arguments list to gather
    some_async_method3()
)

Upvotes: 0

Frank Yellin
Frank Yellin

Reputation: 11297

You can create a function

async def await_none():
    return None

And then change your code to

    some_async_method2() if some_condition else await_none(),

There might be a simpler way of doing this.

Upvotes: 4

Related Questions