Skip to content

*args and **kwargs in Python

Mastering *args and **kwargs in Python: A Comprehensive Guide

Section titled “Mastering *args and **kwargs in Python: A Comprehensive Guide”

Sometimes you do not know in advance how many arguments a function will receive — think of print(), which accepts any number of values. Python solves this with *args and **kwargs, which let a function accept an arbitrary number of positional and keyword arguments. In this guide, we’ll explore packing and unpacking, the correct argument order, and how to pass arguments between functions.

Before arbitrary arguments, recall the two basic kinds:

  • Positional arguments are matched by their position: add(2, 3).
  • Keyword arguments are matched by name: add(x=2, y=3).

*args and **kwargs extend these so a function can take as many as the caller passes.

Putting a single * before a parameter name tells Python to pack all extra positional arguments into a tuple. By convention the parameter is named args, but any name works.

The syntax of *args in Python is as follows:

Syntax
def function_name(*args):
    # args is a tuple of all positional arguments
args_basic.py
def add_all(*args):
    print("args is:", args)     # a tuple
    return sum(args)
 
print(add_all(1, 2, 3))
print(add_all(10, 20, 30, 40))

Output:

command
C:\Users\Your Name> python args_basic.py
args is: (1, 2, 3)
6
args is: (10, 20, 30, 40)
100

Putting a double ** before a parameter name packs all extra keyword arguments into a dictionary. By convention it is named kwargs.

The syntax of **kwargs in Python is as follows:

Syntax
def function_name(**kwargs):
    # kwargs is a dict of all keyword arguments
kwargs_basic.py
def build_profile(**kwargs):
    print("kwargs is:", kwargs)    # a dict
    for key, value in kwargs.items():
        print(f"{key}: {value}")
 
build_profile(name="Alice", age=30, city="Paris")

Output:

command
C:\Users\Your Name> python kwargs_basic.py
kwargs is: {'name': 'Alice', 'age': 30, 'city': 'Paris'}
name: Alice
age: 30
city: Paris

You can mix regular parameters, *args, default parameters, and **kwargs in one function. The order is fixed:

Syntax
def function(positional, *args, keyword_default=value, **kwargs):

The required order is:

  1. Standard positional parameters
  2. *args
  3. Keyword-only / default parameters
  4. **kwargs
combined.py
def order(main, *extras, sauce="ketchup", **details):
    print("Main:", main)
    print("Extras:", extras)
    print("Sauce:", sauce)
    print("Details:", details)
 
order("Burger", "Fries", "Coke", sauce="mayo", size="large", spicy=True)

Output:

command
C:\Users\Your Name> python combined.py
Main: Burger
Extras: ('Fries', 'Coke')
Sauce: mayo
Details: {'size': 'large', 'spicy': True}

Diagram:

diagram argument packing mermaid
How arguments are distributed into parameters

The * and ** operators also work in the opposite direction. When calling a function, * unpacks a list/tuple into positional arguments and ** unpacks a dict into keyword arguments.

unpacking.py
def introduce(name, age, city):
    print(f"{name} is {age} and lives in {city}")
 
# Unpack a list into positional arguments
data = ["Bob", 25, "London"]
introduce(*data)
 
# Unpack a dict into keyword arguments
info = {"name": "Carol", "age": 28, "city": "Berlin"}
introduce(**info)

Output:

command
C:\Users\Your Name> python unpacking.py
Bob is 25 and lives in London
Carol is 28 and lives in Berlin

A common pattern is a wrapper function that accepts anything and passes it straight through to another function. This is how decorators wrap arbitrary functions.

forwarding.py
def logged(func, *args, **kwargs):
    print(f"Calling {func.__name__} with {args} {kwargs}")
    return func(*args, **kwargs)     # forward everything
 
def power(base, exponent):
    return base ** exponent
 
print(logged(power, 2, exponent=10))

Output:

command
C:\Users\Your Name> python forwarding.py
Calling power with (2,) {'exponent': 10}
1024

When a function is called, positional extras are collected into *args as a tuple, and keyword extras are collected into **kwargs as a dict.

diagram Binding f(1, 2, x=3, y=4) mermaid
Positional args flow into the *args tuple; keyword args flow into the **kwargs dict.

*args and **kwargs let functions accept any number of arguments: *args packs extra positional arguments into a tuple, and **kwargs packs extra keyword arguments into a dictionary. The same * and ** operators unpack sequences and dictionaries back into arguments at the call site. Combine them with regular parameters in the fixed order — positional, *args, keyword defaults, **kwargs — and use them to write flexible wrappers and decorators. For more hands-on examples and in-depth tutorials, explore our resources on Python Central Hub!


pch.coffeeTagline

pch.coffeeCta

pch.feedbackHeading

pch.feedbackSubheading