*
is for iterables, and **
is for objects like dict. it works kind of like js spread operator ...
ex.
a = [1, 2, 3, 4, ]
b = {'a': 1, 'b': 2}
print(*a) # 1 2 3 4
print(b) # {'a': 1, 'b': 2}
print(*b) # a b
b = {**b, 'c': 3}
print(b) # {'a': 1, 'b': 2, 'c': 3}
note that print(**b)
won't work, as print take iterable of some values, not a keyword-argument pair like 'a':1
this unpacking is often used in function parameters, when number or parameters are not necessarily decidedneed to be varidic.
ex.
def some_func(*args, **kwargs):
pass
so *args
part is for positianal arguments. They will be stored in a tuple. While you can list all the positional arguments like this...
def some_func(p1,p2,p3,p4,p5,p6):
pass
why not do
def some_func(*args):
pass
some_func(a,b,c,d,e,f)
I guess you can make a list and spread at function call too like this
def some_func(p1,p2,p3,p4,p5,p6):
pass
params = [a,b,c,d,e,f]
some_func(*params)
but not too intuitive, and you would need to pass in the exactly same number of arguments in. what if the function doesn't care about the number of arguments?
ex.
def sum(*args):
r = 0
for arg in args:
r += arg
return r
some_func(1,2,4,5,6,7,8,9,10)
**kwargs
works like *args
but for a dict of keyword arguments. Examples are not provided.
For more info, refer to https://realpython.com/python-kwargs-and-args/#using-the-python-kwargs-variable-in-function-definitions
IMO realpython has some good materials on python overall