Starting with a Clean Slate

*args allow you to pass multiple ( variable sized ) number of arguments to a python function.

General Format:

def function(*args):
    for arg in args:
        ...
# *args becomes an iterable

**kwargs allow you to pass multiple values to a function with a named keyword. **kwargs can then be evaluated as a dictionary inside a function.

General Format:

def function(**kwargs):
    for key,value in kwargs:
        ...
    
#function call
function(name ='Ron', age = '21', height = 175)

Inside the function, a dictionary is created which can be processed as a typical dictionary in python.

The Holy Grail

In Python, functions can be defined to accept a certain number of arguments, which must be defined inside the parentheses of the function. However, there are situations where you may want to create more flexible functions that can accept an unknown number of arguments. This is where *args and **kwargs come in.

*args allows you to pass a variable number of positional arguments to a function. This means that you can pass any number of arguments to the function, without needing to define them in advance.

As an example, let’s say you want to create a function that concatenates a list of strings. You could define the function as follows:

def concatinate(a,b,seperator=''):
    return str(a) + seperator  + str(b)

print(concatinate('Silly','Syntax','-'))
# -> Silly-Syntax

Looks promising right? Here the function accepts two variables and connects them using a separator that the user can choose.

What if we needed to concatenate multiple values? An answer to this would be to use a list. If we use a list then the above function could take any number of values as long as the values are defined inside the list. Lets see some code.

 

def concatinate(words, seperator = ' '):
    return seperator.join(words)
print(concatinate(['Silly','Syntax','is','awesome'],'-'))
# -> Silly-Syntax-is-awesome

What if all the values we see inside the list were separate variables? In this case we can use something called *args  which stands for “arguments”, and allows a function to receive an arbitrary number of positional arguments. This means that you can pass any number of arguments to the function, and they will be collected into a tuple.

def concatinate(*args,seperator=' '):
    return seperator.join(args)

print(concatinate('I','am','Aadarsh','and','i','am','21',seperator=' '))
# -> I am Aadarsh and i am 21

So what *args allows is that you can take more arguments that the formal arguments that you previously defined.

**kwargs

**kwargs (keyword argument) is similar to *args but you can pass any number of arguments to the function, and they will be collected into a dictionary. While calling a function,  a value is assigned to a keyword or an identifier for example 'name='john' then the key of the dictionary will be name and the value will be ‘john’ Here’s an example:

def my_function(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

my_function(name='Ron', age=30, city='Miami')
# name: Ron
# age: 30
# city: Miami

Here is a better use of **kwargs:

class Person:
    def __init__(self, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)

person = Person(name='John', age=30, city='New York')
print(person.name) # Output: John
print(person.age) # Output: 30
print(person.city) # Output: New York

A brief explanation of the above code is given below

The __init__() method is the constructor method for the Person class, which is called when a new instance of the class is created. In this case, the constructor method accepts a variable number of keyword arguments using **kwargs.

The for loop in the __init__() method iterates over each key-value pair in kwargs using the items() method. For each key-value pair, the setattr() method is used to set the attribute of the self object with the corresponding key and value. This dynamically adds attributes to the self object based on the keyword arguments provided during instantiation.

After defining the Person class, the code creates a new instance of the class named person using the Person() constructor method with the name, age, and city keyword arguments. Finally, the code prints the values of the name, age, and city attributes of the person object using the dot notation.

Here is another example where both *args and **kwargs are used.

 

def print_details(*args, **kwargs):
    print("Positional arguments:")
    for arg in args:
        print(arg)
        
    print("\nKeyword arguments:")
    for key, value in kwargs.items():
        print(key, "=", value)
        
print_details("John", "Doe", age=30, city="New York")
# Results ->
# Positional arguments:
# John
# Doe

# Keyword arguments:
# age = 30
# city = New York

In this example, the print_details() function takes both variable-length positional arguments *args and variable-length keyword arguments **kwargs.

The *args parameter allows the function to accept any number of positional arguments. In this example, we’re passing two positional arguments, “John” and “Doe”.

The **kwargs parameter allows the function to accept any number of keyword arguments as a dictionary. In this example, we’re passing two keyword arguments, “age” with a value of 30, and “city” with a value of “New York”.

The function then iterates over both args and kwargs and prints the positional and keyword arguments respectively.

Summary

  • *args is used to pass a variable number of positional arguments to a function. It allows you to pass any number of arguments to the function.

  • **kwargs is used to pass a variable number of keyword arguments to a function. It allows you to pass any number of named arguments to the function.

  • The names args and kwargs are conventions, and you can use any valid variable names. However, using these names makes your code more readable and understandable.

  • When you use *args and **kwargs, you can pass any number of arguments to the function without knowing in advance how many arguments will be passed.

  • You can use *args and **kwargs together in a function to accept any number and combination of arguments.

  • In a function definition, *args must come before **kwargs. When calling a function, positional arguments must come before keyword arguments.

  • When using **kwargs, the argument names must be valid Python identifiers, and the values can be of any data type.

  • You can use *args and **kwargs in a variety of scenarios, such as creating flexible and extensible functions, handling variable-length input in Flask forms, and more.

Leave a Reply

Your email address will not be published. Required fields are marked *