I know that the asterisk is used to unpack values like system args or when you unpack lists into variables.
But I have not seen this syntax here before in this example of asyncio.
I was reading this article here, https://realpython.com/async-io-python/#the-10000-foot-view-of-async-io , but I don't understand what the asterisk operator is doing in this context.
#!/usr/bin/env python3
# rand.py
import asyncio
import random
# ANSI colors
c = (
"\033[0m", # End of color
"\033[36m", # Cyan
"\033[91m", # Red
"\033[35m", # Magenta
)
async def makerandom(idx: int, threshold: int = 6) -> int:
print(c[idx 1] f"Initiated makerandom({idx}).")
i = random.randint(0, 10)
while i <= threshold:
print(c[idx 1] f"makerandom({idx}) == {i} too low; retrying.")
await asyncio.sleep(idx 1)
i = random.randint(0, 10)
print(c[idx 1] f"---> Finished: makerandom({idx}) == {i}" c[0])
return i
async def main():
res = await asyncio.gather(*(makerandom(i, 10 - i - 1) for i in range(3)))
return res
if __name__ == "__main__":
random.seed(444)
r1, r2, r3 = asyncio.run(main())
print()
print(f"r1: {r1}, r2: {r2}, r3: {r3}")
Under the async def main function
right before the makerandom
there is an asterisk. Could someone explain what it does in this context ? I am trying to understand how async / await works.
I looked at this answer, Python asterisk before function but it doesn't really explain it.
CodePudding user response:
The asterisk isn't before makerandom
, it's before the generator expression
(makerandom(i, 10 - i - 1) for i in range(3))
asyncio.gather
doesn't take an iterable as its first argument; it accepts a variable number of awaitables as positional arguments. In order to get from a generator expression to that, you need to unpack the generator.
In this particular instance, the asterisk unpacks
asyncio.gather(*(makerandom(i, 10 - i - 1) for i in range(3)))
into
asyncio.gather(makerandom(0, 9), makerandom(1, 8), makerandom(2, 7))
CodePudding user response:
An asterisk, means unpacking. It spreads the iterable into several arguments as in:
array = [1, 2, 3]
print(*array)
would be the same as
print(1, 2, 3)
Another example:
generator = (x for x in range(10) if my_function(x))
print(*generator)
One asterisk is being used for ordinary iterables, but when it comes to mappings, you can also use double-asterisk as **
in order to unpack the mapping into keyword arguments, as in:
dictionary = {"hello": 1, "world": 2}
my_function(**dictionary)
This would be equivalent to my_function(hello=1, world=2)
.
You can also use the ordinary one-asterisk in order to only unpack the keys from the mapping:
print(*{"hello": 1, "world": 2})
This would result in hello world