A beginner programmer would answer that '*' is used for multiplication but that is not what we want. The '*' and '**' used for unpacking lists and dictionaries. This functionality more often uses for function's params.

As you know we can send params in function in two ways: with-param name and without. Params which was sent without name store inside args list and with the name inside kwargs dictionary. This functionality very useful and for sending params (Second call).

def test_function(*args, **kwargs):
    print(f"You sent these properties as args: {args}")
    print(f"You sent these properties as kwargs: {kwargs}")

print("First call:")
test_function("a", "b", "c", d="d", e="e", f="f")

param_list = ["a", "b", "c"]
param_dict = {
    "d": "d",
    "e": "e",
    "f": "f"
}
print("Second call:")
test_function(*param_list, **param_dict)

Output:

First call:
You sent these properties as args: ('a', 'b', 'c')
You sent these properties as kwargs: {'d': 'd', 'e': 'e', 'f': 'f'}
Second call:
You sent these properties as args: ('a', 'b', 'c')
You sent these properties as kwargs: {'d': 'd', 'e': 'e', 'f': 'f'}