Understanding Python *args
and **kwargs
Python *args and **kwargs are special syntaxes that allow a function to accept a variable number of arguments. They are used when unsure how many arguments might be passed to your function. The *args syntax collects extra positional arguments into a tuple, while **kwargs collects extra keyword arguments into a dictionary. These features make functions much more flexible, as they can gracefully handle different numbers of arguments without needing to define each one explicitly. Python *args and **kwargs are especially useful when writing functions that must be generic and reusable in various contexts.
Syntax of Python *args
and **kwargs
def my_function(*args, **kwargs):
# Function body
Explanation
def my_function(
: Defines a function namedmy_function
.*args
: Collects all extra positional arguments into a tuple namedargs
.**kwargs
: Collects all extra keyword arguments into a dictionary namedkwargs
.# Function body
: The code that the function will execute.
Example of Python *args
and **kwargs
def example_function(*args, **kwargs):
print("args:", args)
print("kwargs:", kwargs)
example_function(1, 2, 3, a=4, b=5)
Explanation
def example_function(*args, **kwargs):
: Defines a function namedexample_function
that accepts any number of positional and keyword arguments.print("args:", args)
: Prints the tupleargs
.print("kwargs:", kwargs)
: Prints the dictionarykwargs
.example_function(1, 2, 3, a=4, b=5)
: Calls the function with three positional arguments and two keyword arguments.
Output
args: (1, 2, 3)
kwargs: {‘a’: 4, ‘b’: 5}
Function without Python *args
and **kwargs
A function defined without *args and **kwargs in Python has a fixed number of parameters. When calling such a function, you must provide arguments that exactly match the parameters in the function definition, both in number and type (positional or keyword). If you provide too few or too many arguments, or if you use keyword arguments for parameters that aren’t defined to accept them, Python will raise a TypeError. This kind of function definition is less flexible but can be more straightforward when the number and type of inputs are known and fixed.
Syntax
def my_function(arg1, arg2, kwarg1=default_value, kwarg2=default_value):
# Function body
Explanation
def my_function(
: Defines a function namedmy_function
.arg1, arg2
: Required positional arguments.kwarg1=default_value, kwarg2=default_value
: Optional keyword arguments with default values.# Function body
: Code that the function will execute.
Example
def fixed_function(a, b, c=3):
print("a:", a)
print("b:", b)
print("c:", c)
fixed_function(1, 2)
Explanation
def fixed_function(a, b, c=3):
: Definesfixed_function
with two required arguments (a
,b
) and one optional argumentc
with a default value of 3.print("a:", a)
: Prints the value ofa
.print("b:", b)
: Prints the value ofb
.print("c:", c)
: Prints the value ofc
.fixed_function(1, 2)
: Callsfixed_function
with values fora
andb
.c
will take its default value.
Output
a: 1
b: 2
c: 3
Python *args
Python *args is used in a function definition to allow the function to accept any number of positional arguments. These arguments are collected into a tuple named args within the function. It is a way to pass a variable-length list of arguments to your function. Inside the function, you can iterate over the args tuple to access each argument passed.
Syntax
def my_function(*args):
# Function body
Explanation
def my_function(
: Defines a function namedmy_function
.*args
: Syntax allows the function to accept any number of positional arguments, which are then packed into a tuple namedargs
.# Function body
: This is where you write the code that will use theargs
tuple.
Example
def sum_all(*args):
total = 0
for number in args:
total += number
return total
result = sum_all(1, 2, 3, 4)
print(result)
Explanation
def sum_all(*args):
: Defines a functionsum_all
that accepts any number of arguments and stores them in a tuple namedargs
.total = 0
: Initializes a variabletotal
to 0.for number in args:
: Loop iterates over each element in theargs
tuple.total += number
: Adds eachnumber
to thetotal
.return total
: Returns the final sum.result = sum_all(1, 2, 3, 4)
: Callssum_all
with four arguments and stores the result inresult
.print(result)
: Prints theresult
, which is the sum of the arguments.
Output
10
When to use *args
?
You should use *args when you want to create a function that can handle an arbitrary number of positional arguments. This is particularly useful when you don’t know how many arguments will be passed to the function. A typical example is when you’re writing a function that operates on a set of values, like summing them up, where the number of values can vary.
Syntax
def my_function(*args):
# Code that uses the args tuple
Explanation
def my_function(
: Defines a function namedmy_function
.*args
: Allowsmy_function
to accept any number of positional arguments. The*
unpacks the arguments into the tupleargs
.# Code that uses the args tuple
: Where you write the code to process the arguments.
Example
def print_arguments(*args):
for arg in args:
print(arg)
print_arguments('apple', 'banana', 'cherry')
Explanation
def print_arguments(*args):
: Defines a functionprint_arguments
that accepts any number of arguments.for arg in args:
: Loop iterates through each argument in theargs
tuple.print(arg)
: Prints the current argument.print_arguments('apple', 'banana', 'cherry')
: Callsprint_arguments
with three string arguments.
Output
apple
banana
cherry
Python **kwargs
Python **kwargs is used in a function definition to allow the function to accept any number of keyword arguments. These arguments are collected into a dictionary named kwargs within the function. Each key in the kwargs dictionary corresponds to the keyword used when calling the function; the value is associated with that keyword. It’s like having a flexible set of named parameters that your function can accept.
Syntax
def my_function(**kwargs):
# Function body
Explanation
def my_function(
: Defines a function namedmy_function
.**kwargs
: Syntax allows the function to accept any number of keyword arguments, which are then packed into a dictionary namedkwargs
.# Function body
: Where you write the code that will use thekwargs
dictionary.
Example
def describe_person(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
describe_person(name="Alice", age=30, city="New York")
Explanation
def describe_person(**kwargs):
: Defines a functiondescribe_person
that accepts any number of keyword arguments.for key, value in kwargs.items():
: Loop iterates over the key-value pairs in thekwargs
dictionary.print(f"{key}: {value}")
: Prints each key-value pair.describe_person(name="Alice", age=30, city="New York")
: Callsdescribe_person
with three keyword arguments.
Output
name: Alice
age: 30
city: New York
When to use **kwargs
?
You should use **kwargs when you want to create a function that can handle an arbitrary number of keyword arguments. This is particularly useful when you’re not sure in advance what named parameters might be passed to your function. Using **kwargs makes your function more adaptable, as it can accept and process additional named parameters without changing the function’s definition. A common use case is when you’re creating functions that set or modify options or settings, where the number and names of the options can vary.
Syntax
def my_function(**kwargs):
# Code that uses the kwargs dictionary
Explanation
def my_function(
: Defines a function namedmy_function
.**kwargs
: Allowsmy_function
to accept any number of keyword arguments. The**
unpacks the arguments into the dictionarykwargs
.# Code that uses the kwargs dictionary
: Where you write the code to process the keyword arguments.
Example
def set_attributes(**kwargs):
attributes = {}
for key, value in kwargs.items():
attributes[key] = value
print(attributes)
set_attributes(color="red", size="large", material="wood")
Explanation
def set_attributes(**kwargs):
: Defines a functionset_attributes
that accepts any number of keyword arguments.attributes = {}
: Initializes an empty dictionary calledattributes
.for key, value in kwargs.items():
: Loop iterates through thekwargs
dictionary.attributes[key] = value
: Adds each key-value pair fromkwargs
to theattributes
dictionary.print(attributes)
: Prints theattributes
dictionary.set_attributes(color="red", size="large", material="wood")
: Callsset_attributes
with three keyword arguments.
Output
{‘color’: ‘red’, ‘size’: ‘large’, ‘material’: ‘wood’}
Ordering Arguments
When defining a function in Python, you should follow a specific order for different types of arguments. First, you list the standard positional arguments. Then comes the *args, which collects any extra positional arguments. After that, you can define any keyword-only arguments, and finally, you can use **kwargs to collect any remaining keyword arguments. Following this order ensures that Python can correctly match the arguments passed to the function with the parameters in the function definition.
Syntax
def my_function(pos_arg1, pos_arg2, *args, kw_only_arg1, kw_only_arg2, **kwargs):
# Function body
Explanation
def my_function(
: Defines a function namedmy_function
.pos_arg1, pos_arg2
: Standard positional arguments.*args
: Collects any extra positional arguments into a tuple.kw_only_arg1, kw_only_arg2
: Keyword-only arguments. They must be specified by name when calling the function.**kwargs
: Collects any remaining keyword arguments into a dictionary.# Function body
: Where you write the code that the function will execute.
Example
def example_function(a, b, *args, c=None, d=None, **kwargs):
print("a:", a)
print("b:", b)
print("args:", args)
print("c:", c)
print("d:", d)
print("kwargs:", kwargs)
example_function(1, 2, 3, 4, 5, c=6, d=7, e=8, f=9)
Explanation
def example_function(a, b, *args, c=None, d=None, **kwargs):
: Definesexample_function
with two positional arguments (a
,b
),*args
, two keyword-only arguments (c
,d
), and**kwargs
.print("a:", a)
: Prints the value ofa
.print("b:", b)
: Prints the value ofb
.print("args:", args)
: Prints theargs
tuple.print("c:", c)
: Prints the value ofc
.print("d:", d)
: Prints the value ofd
.print("kwargs:", kwargs)
: Prints thekwargs
dictionary.example_function(1, 2, 3, 4, 5, c=6, d=7, e=8, f=9)
: Calls the function with various arguments.
Output
a: 1
b: 2
args: (3, 4, 5)
c: 6
d: 7
kwargs: {‘e’: 8, ‘f’: 9}
Python *args
and **kwargs
to Call a Function
You can use both *args and **kwargs to call a function in Python, which is especially useful when you want to pass arguments from one function to another. The *args syntax unpacks a sequence (like a tuple or list) into positional arguments, while **kwargs unpacks a dictionary into keyword arguments. This technique allows a function to accept arguments flexibly and then pass them along to another function, even if the second function has a different signature.
Syntax
def another_function(arg1, arg2, kwarg1=None, kwarg2=None):
# Function body
def my_function(*args, **kwargs):
another_function(*args, **kwargs)
Explanation
def another_function(
: Defines a function namedanother_function
which will be called usingmy_function
.arg1, arg2
: Positional arguments foranother_function
.kwarg1=None, kwarg2=None
: Keyword arguments with default values foranother_function
.def my_function(*args, **kwargs):
: Definesmy_function
that accepts any number of positional and keyword arguments.another_function(*args, **kwargs)
: Callsanother_function
, unpackingargs
into positional arguments andkwargs
into keyword arguments.
Example
def another_function(a, b, c=None, d=None):
print("a:", a)
print("b:", b)
print("c:", c)
print("d:", d)
def caller_function(*args, **kwargs):
another_function(*args, **kwargs)
caller_function(1, 2, d=4)
Explanation
def another_function(a, b, c=None, d=None):
: Definesanother_function
which accepts two positional arguments and two keyword arguments.print("a:", a)
: Prints the value ofa
.print("b:", b)
: Prints the value ofb
.print("c:", c)
: Prints the value ofc
.print("d:", d)
: Prints the value ofd
.def caller_function(*args, **kwargs):
: Definescaller_function
which accepts any number of positional and keyword arguments.caller_function(1, 2, d=4)
: Callscaller_function
with positional arguments1
,2
and a keyword argumentd=4
.
Output
a: 1
b: 2
c: None
d: 4
Python *args
and **kwargs
to Set Values of Object
You can use both *args and **kwargs in a class’s __init__ method to set attributes of an object dynamically. The *args can initialize attributes with positional arguments, while **kwargs allows setting attributes using keyword arguments. This gives you much flexibility when creating objects, as you don’t have to define each attribute explicitly in the constructor. It’s handy when the attributes of an object vary depending on how it’s used.
Syntax
class MyClass:
def __init__(self, *args, **kwargs):
# Initialize attributes using args and kwargs
Explanation
class MyClass:
: Defines a class namedMyClass
.def __init__(self, *args, **kwargs):
: Constructor forMyClass
. It accepts any number of positional (*args
) and keyword (**kwargs
) arguments.# Initialize attributes using args and kwargs
: Where you write the code to set the object’s attributes based on the provided arguments.
Example
class MyClass:
def __init__(self, *args, **kwargs):
self.args = args
for key, value in kwargs.items():
setattr(self, key, value)
my_object = MyClass(1, 2, 3, a=4, b=5)
print(my_object.args)
print(my_object.a)
print(my_object.b)
Explanation
class MyClass:
: Defines a class namedMyClass
.def __init__(self, *args, **kwargs):
: Constructor, accepting any number of positional and keyword arguments.self.args = args
: Assigns the positional arguments to an attribute namedargs
.for key, value in kwargs.items():
: Loop iterates through the keyword arguments.setattr(self, key, value)
: Sets an attribute on the object with the namekey
and the valuevalue
.my_object = MyClass(1, 2, 3, a=4, b=5)
: Creates an object ofMyClass
with some arguments.print(my_object.args)
: Prints theargs
attribute.print(my_object.a)
: Prints thea
attribute.print(my_object.b)
: Prints theb
attribute.
Output
(1, 2, 3)
4
5
Packing and Unpacking Using Both *args
and **kwargs
in Python
Packing and unpacking are powerful features in Python that are often used in conjunction with *args and **kwargs. Packing involves collecting multiple values into a single variable (e.g., a tuple for positional arguments with *args and a dictionary for keyword arguments with **kwargs). Unpacking is the reverse: taking a sequence or a dictionary and spreading its elements as individual arguments to a function call. This allows for dynamic and flexible function definitions and calls and elegant ways to handle data structures.
Syntax
# Packing
def my_function(*args, **kwargs):
# args is a tuple, kwargs is a dictionary
# Unpacking
my_function(*my_list, **my_dictionary)
Explanation
# Packing
: Comment indicates that the following code demonstrates packing.def my_function(*args, **kwargs):
: Defines a function that packs extra arguments intoargs
(tuple) andkwargs
(dictionary).# args is a tuple, kwargs is a dictionary
: Comment explains the data types ofargs
andkwargs
.# Unpacking
: Comment indicates that the following code demonstrates unpacking.my_function(*my_list, **my_dictionary)
: Callsmy_function
, unpackingmy_list
into positional arguments andmy_dictionary
into keyword arguments.
Example
def my_function(a, b, c, d=4, e=5):
print(a, b, c, d, e)
my_list = [1, 2, 3]
my_dict = {'d': 40, 'e': 50}
my_function(*my_list, **my_dict)
Explanation
def my_function(a, b, c, d=4, e=5):
: Defines a functionmy_function
with three positional arguments and two keyword arguments with default values.print(a, b, c, d, e)
: Prints the values of the arguments.my_list = [1, 2, 3]
: Creates a listmy_list
.my_dict = {'d': 40, 'e': 50}
: Creates a dictionarymy_dict
.my_function(*my_list, **my_dict)
: Callsmy_function
, unpackingmy_list
into positional argumentsa
,b
,c
, andmy_dict
into keyword argumentsd
,e
.
Output
1 2 3 40 50
Things to Remember
There are a few key things to remember when using *args and **kwargs in Python. First, *args must come before **kwargs in a function definition. Second, the names “args” and “kwargs” are just conventions; you could technically use any valid variable names preceded by * or **, but it’s best practice to stick with “args” and “kwargs” for clarity. Third, remember that *args collects extra positional arguments into a tuple, while **kwargs collects extra keyword arguments into a dictionary. Finally, using *args and **kwargs can make your code more flexible but also make it less readable if overused, so use them judiciously.
Conclusion
Python *args and **kwargs are powerful features that add flexibility to your functions by allowing them to accept various arguments. *args handles any positional arguments, packing them into a tuple, while **kwargs handles any number of keyword arguments, packing them into a dictionary. Understanding how to use these features, the proper ordering of arguments, and the principles of packing and unpacking are essential for writing reusable Python code. They are especially useful in function forwarding, subclassing, and creating functions that operate on various inputs or options. While they offer great flexibility, using them thoughtfully is important to maintain code readability and avoid potential confusion.