If we take a look at your example:
test(test=1, asterisk=2)
is more readable than
t = {"test":1, "asterisk":2}
test2(t)
or
test2({"test":1, "asterisk":2})
So if you have a function that can accept a variable number of variably named arguments, that's the most readable way of doing it.
It works the other way too:
def add(a, b):
return a + b
params = { "b": 5, "a": 6}
print(add(**params))
11
*args will give you a variable number of arguments:
def min(*args):
min = None
for v in args:
if min is None or v < min:
min = v
return min
print(min(1, 7, 8, 9, 2, 1, 0))
0
This also works the other way:
def add(a, b):
return a + b
t = [5, 6]
print(add(*t))
11
Both are used when wrapping other functions, like when creating function decorators:
def log_call(f):
def logged(*args, **kwargs):
print("Called {}".format(f.__name__))
return f(*args, **kwargs)
return logged
class A:
@log_call
def add_two_numbers(self):
return 1 + 2
print(A().add_two_numbers())
Called add_two_numbers
3