Python
Programming
Coding Concepts
Function Arguments
Advanced Python Syntax

Use of *args and **kwargs

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

*args and **kwargs let a Python function accept a flexible number of arguments. They are useful when you are writing wrappers, forwarding calls, or designing APIs that need optional extra input without exploding the function signature.

What *args Actually Captures

*args collects extra positional arguments into a tuple.

python
1def add_all(*args):
2    return sum(args)
3
4
5print(add_all(1, 2, 3))
6print(add_all(10, 20, 30, 40))

Output:

text
6
100

The name args is conventional, but not magical. This works too:

python
def add_all(*numbers):
    return sum(numbers)

What matters is the leading *, not the variable name.

What **kwargs Captures

**kwargs collects extra keyword arguments into a dictionary.

python
1def build_profile(name, **kwargs):
2    profile = {"name": name}
3    profile.update(kwargs)
4    return profile
5
6
7print(build_profile("Ada", role="Engineer", language="Python"))

Output:

text
{'name': 'Ada', 'role': 'Engineer', 'language': 'Python'}

Again, the name kwargs is a convention. The ** is what tells Python to pack remaining named arguments into a mapping.

Inside a function definition, *args and **kwargs pack values together. At a call site, * and ** can unpack values back out.

python
1def greet(first_name, last_name, punctuation="!"):
2    return f"Hello, {first_name} {last_name}{punctuation}"
3
4
5parts = ("Grace", "Hopper")
6options = {"punctuation": "."}
7
8print(greet(*parts, **options))

Output:

text
Hello, Grace Hopper.

This symmetry is why *args and **kwargs are so common in wrapper functions. You can accept flexible input and forward it with very little boilerplate.

A Useful Wrapper Example

Here is a simple timing decorator that forwards any positional and keyword arguments to the wrapped function:

python
1import time
2
3
4def timed(func):
5    def wrapper(*args, **kwargs):
6        start = time.perf_counter()
7        try:
8            return func(*args, **kwargs)
9        finally:
10            elapsed = time.perf_counter() - start
11            print(f"{func.__name__} took {elapsed:.6f}s")
12
13    return wrapper
14
15
16@timed
17def multiply(a, b, scale=1):
18    return a * b * scale
19
20
21print(multiply(3, 4, scale=2))

Without *args and **kwargs, writing reusable wrappers like this would be much more awkward.

Parameter Order Still Matters

Python still enforces parameter ordering rules. A common pattern is:

python
1def example(required, *args, debug=False, **kwargs):
2    print(required)
3    print(args)
4    print(debug)
5    print(kwargs)
6
7
8example("run", 1, 2, 3, debug=True, mode="fast")

Here:

  • 'required is a normal positional-or-keyword parameter'
  • '*args collects extra positional values'
  • 'debug becomes keyword-only because it appears after *args'
  • '**kwargs collects any remaining named values'

Understanding that order makes function signatures much easier to read.

When They Are Helpful

Good uses include:

  • decorators and wrappers
  • pass-through helper functions
  • plugin hooks that may accept optional metadata
  • APIs that intentionally allow extra named options

Not every function needs them. If a function always expects exactly three clear parameters, explicit names are usually better than flexible catch-all parameters.

Common Pitfalls

The biggest mistake is using *args or **kwargs when the function really has a fixed, known contract. That makes code harder to read and hides what callers are supposed to provide.

Another common issue is forgetting that args is a tuple and kwargs is a dictionary. They are collected containers, not magic argument streams.

Developers also sometimes mix up packing and unpacking. def f(*args) packs extra positional values in a definition, while f(*values) unpacks an iterable at a call site.

Finally, forwarding **kwargs blindly can hide misspelled option names. If the receiving function does not expect a key, the error may show up far away from where the bad value entered the system.

Summary

  • '*args collects extra positional arguments into a tuple.'
  • '**kwargs collects extra keyword arguments into a dictionary.'
  • The same * and ** syntax can unpack values at call sites.
  • They are especially useful in wrappers, decorators, and pass-through helpers.
  • Use them for flexibility, but prefer explicit parameters when the contract is fixed and known.

Course illustration
Course illustration

All Rights Reserved.