When to use python args and kwargs

python
calmcodes
Let’s learn some from calmcode, thanks Vincent Warmerdam!
Author

Jakob Johannesson

Published

July 16, 2024

Tip

Today I’ll do some python testing

Regular function

def function(a,b):
  return a*b

df=function(1,2)
print(df)
2

Using args

Args stands for arguments. Think of it like a unnamed list. It can be used to pass a variable number of arguments to a function. The * before the parameter name tells Python to pack all arguments into this tuple.

def function(*args):
  print(type(args))
  for arg in args:
    print(arg)

function("a","b")
<class 'tuple'>
a
b

Quite useful! But it does not allow you to give them a name, so it might not be as useful as the next function: Kwargs!

Using kwargs

kwargs stands for keyword arguments and is a named arguments you can send into a function. use ** to assign it and it will go in there and do wonders. it will return a dict.

def function(**kwargs):
  print(type(kwargs))
  for key, value in kwargs.items():
    print(key,value)


function(key_a="value_a",key_b="value_b")
<class 'dict'>
key_a value_a
key_b value_b

As you can see, it is great. But it is not very useful if you want to pass a dataframe into the function and then add columns to it. This is where pandas comes in handy.

Using kwargs with pandas

import pandas as pd
df = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})


def function(**kwargs):
    print(type(kwargs))
    for key, value in kwargs.items():
        df[key] = value
    return df

df = function(C=[5,2],D=[7,8])
print(df)
<class 'dict'>
   A  B  C  D
0  1  3  5  7
1  2  4  2  8

Postition is important!

An common error that can occur is if you mix named and unnamed (args and kwargs) in a bad order. Let’s create an example, this works:

def func(a,b,*args,booloean = True, **kwargs):
    print(a,b)
    print(args)
    print(booloean)
    print(kwargs)
    
func(1,2,3,4,5,keyword=False,param = 'horse')
1 2
(3, 4, 5)
True
{'keyword': False, 'param': 'horse'}

Let’s add a few more unnamed arguments to the mix. It will break due to the position of the arguments.

def func(a,b,*args,booloean = True, **kwargs):
    print(a,b)
    print(args)
    print(booloean)
    print(kwargs)
    
func(1,2,3,4,5,keyword=False, 2,3,param = 'horse')
Warning

SyntaxError: positional argument follows keyword argument.

I can’t add “2,3” in that position, because python will handle the unnamed arguments first, then the named ones.

Unpacking a dict into a function

def func(a,b,*args,booloean = True, **kwargs):
    print(a,b)
    print(args)
    print(booloean)
    print(kwargs)

input = {'param_a': 'test', 'param_b': 'fest'}
func(1,2,3,4,5,keyword=False, param = 'horse', **input)
1 2
(3, 4, 5)
True
{'keyword': False, 'param': 'horse', 'param_a': 'test', 'param_b': 'fest'}

When to use it?

Useful if you want to write cleaner code!

import json
import pathlib

def dict_to_config(dictionary, config="config.json", verbose = False,**kwargs):
    json_txt = json.dumps(dictionary, **kwargs)
    if verbose==True:
        print(json_txt)
    pathlib.Path(config).write_text(json_txt)

dict_to_config({"a": 'yes',"b": 'no'},verbose=True)
{"a": "yes", "b": "no"}

Now I can access all the functionallity from the json.dumps, without having to type out all the code for it. Let’s try it.

dict_to_config({"a": 'yes',"b": 'no'},verbose=True, indent = 2)
{
  "a": "yes",
  "b": "no"
}

It works! Thanks to calmcode, this was fun.