# *Args And **Kwargs

While dealing with arguments in functions , It becomes a necessity to specify the number of arguments the function will be dealing with within the function declaration itself , However this can be a problem when you want your function to take in any arbitary number of arguments. This is where *args and **kwargs are used.

*args ( pronounced as ‘star arguments’) allows a function to take any arbitary number of arguments and stores it in form of a tuple while **kwargs ( pronounced as ‘double star keyword arguments’ ) allows a function to take any arbitary number of arguments in form of a ( key , value ) pair and stores it in form of a dictionary.

Let us take an example on this.

``def my_func_1(*args):    print(args)  def my_func_2(**kwargs):    print(kwargs)      my_func_1(1,2,3,4,5)  my_func_2(one = 'me', two = 'you')``

output:
``(1, 2, 3, 4, 5)  {'one': 'me', 'two': 'you'}`` Note that there is no speciality in terms ‘args’ and ‘kwargs’ rather all the speciality lies in ‘*’ and ‘**’.This means that function can take *p_1 and **p_2 as arguments and essentially have the same impact as *args and **kwargs. Often , you’ll want to grab individual arguments from the tuple and dictionary and for that a ‘loop’ is used. Let us see an example on this.

In the example below , i want to find out the product of the numbers passed as arguments to the function.

``def my_func(*args):    p=1    for x in args:      p=x*p    return p      print(my_func(1,2,3,4,5,6,7,8,9,10)) ``

output:
``3628800``

It is also possible for a function to take both *args and **kwargs as arguments , However kindly make sure to pass arguments in that order. Let us see an example on this.

``def my_func(*args,**kwargs):    print(args)    print(kwargs)  my_func(1,2,3,4,5,6,7,8,one='1',two='2',three='3') ``

output:
``(1, 2, 3, 4, 5, 6, 7, 8)  {'one': '1', 'two': '2', 'three': '3'}``