All Courses
Advanced Python

Python `*args` and `**kwargs`

Two Separate Concepts

*args **kwargs
Full name Arguments Keyword Arguments
Stores Any number of positional arguments Any number of keyword arguments
Data type stored in Tuple Dictionary
Number of asterisks One * Two **

The names args and kwargs are conventions — you can use any name (e.g. *values, **options). The asterisks are what matter.


*args — As a Parameter

Allows a function to accept any number of positional arguments:

def sum_items(*args):
    print(args)       # tuple of all passed arguments
    print(sum(args))

sum_items(1, 2, 3)        # (1, 2, 3) → 6
sum_items(1, 2, 3, 4)     # (1, 2, 3, 4) → 10
sum_items(1)              # (1,) → 1
sum_items()               # () → 0

**kwargs — As a Parameter

Allows a function to accept any number of keyword arguments:

def show(**kwargs):
    print(kwargs)   # dictionary of all keyword arguments

show(k=2, a=3)     # {'k': 2, 'a': 3}

Access a specific keyword argument:

def show(**kwargs):
    print(kwargs["k"])

show(k=2, a=3)   # 2

Using Both Together

def test(*args, **kwargs):
    print(args)    # tuple of positional args
    print(kwargs)  # dict of keyword args

test(1, 2, k=3)
# (1, 2)
# {'k': 3}

With a required parameter before *args

def test(p1, *args, **kwargs):
    print(p1, args, kwargs)

test(4, 1, 2, s=1, hello=4, k=True)
# 4  (1, 2)  {'s': 1, 'hello': 4, 'k': True}

test()   # ❌ TypeError — p1 is required

Parameter order rule: required params*args**kwargs


* as an Argument — Unpacking an Iterable (Splat)

Use * when calling a function to unpack a list/tuple/string into individual positional arguments:

def sum_items(a, b, c):
    return a + b + c

my_args = [4, 5, 7]
result = sum_items(*my_args)   # same as sum_items(4, 5, 7)
print(result)                  # 16

Works on any ordered iterable:

sum_items(*[4, 5, 7])    # list  ✅
sum_items(*(4, 5, 7))    # tuple ✅

Practical use — clean printing without brackets

values = [1, 2, 3, 4, 5]

print(values)    # [1, 2, 3, 4, 5]  — includes brackets
print(*values)   # 1 2 3 4 5        — individual values, space-separated

This works because print() itself uses *args internally — it accepts any number of positional arguments.


** as an Argument — Unpacking a Dictionary

Use ** when calling a function to unpack a dictionary into keyword arguments:

def sum_items(a, b, c):
    print(a, b, c)
    return a + b + c

kwargs = {"a": 5, "b": 5, "c": 10}
result = sum_items(**kwargs)   # same as sum_items(a=5, b=5, c=10)
print(result)                  # 20

Using Both When Calling a Function

def test(p1, *args, **kwargs):
    print(p1, args, kwargs)

values = [1, 2]
kw = {"s": 1, "hello": 4, "k": True}

test(4, *values, **kw)
# 4  (1, 2)  {'s': 1, 'hello': 4, 'k': True}

Parameter vs Argument — Summary

Context Syntax What it does
Parameter (defining a function) *args Accepts unlimited positional args → stored as tuple
Parameter (defining a function) **kwargs Accepts unlimited keyword args → stored as dict
Argument (calling a function) *my_list Unpacks list/tuple into individual positional args
Argument (calling a function) **my_dict Unpacks dict into individual keyword args

Key Takeaways & Recap

Concept Summary
*args as param Accepts any number of positional args; stored as a tuple
**kwargs as param Accepts any number of keyword args; stored as a dict
*iterable as arg Unpacks a list/tuple/string into separate positional arguments
**dict as arg Unpacks a dictionary into separate keyword arguments
Why ** for kwargs? Dicts are key-value pairs — two asterisks unpack key=value format
Parameter order normal*args**kwargs
Real-world use print(*values) works because print uses *args internally