coding
parameters
double star/asterisk
asterisk

What does ** (double star/asterisk) and * (star/asterisk) do for parameters?

Master System Design with Codemia

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

Introduction

In Python, * and ** change how function arguments are received or passed. They are small symbols, but they control several important behaviors: collecting extra arguments, forcing keyword-only parameters, and unpacking existing values into a function call.

*args Collects Extra Positional Arguments

When * appears before a parameter name in a function definition, Python gathers any extra positional arguments into a tuple.

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

Here, numbers is a tuple. The name args is conventional, but not special. *values works the same way.

This is useful when the function should accept an open-ended list of positional inputs without forcing callers to build a list first.

**kwargs Collects Extra Keyword Arguments

When ** appears before a parameter name, Python gathers extra keyword arguments into a dictionary.

python
1def describe_user(**info):
2    for key, value in sorted(info.items()):
3        print(f"{key} = {value}")
4
5
6describe_user(name="Alice", role="admin", active=True)

In this case, info is a dictionary like {"name": "Alice", "role": "admin", "active": True}. Again, kwargs is just a naming convention.

This pattern is common in wrapper functions, configuration helpers, and APIs that forward options to another function.

A Bare * Marks Keyword-Only Parameters

There is another important use of * that many beginners miss. A bare * in a parameter list means "everything after this must be passed by keyword."

python
1def connect(host, port, *, timeout=5, use_ssl=False):
2    return host, port, timeout, use_ssl
3
4
5print(connect("localhost", 5432, timeout=10, use_ssl=True))

That call works, but this one would fail:

python
# connect("localhost", 5432, 10, True)

Keyword-only parameters make function calls clearer because the meaning of each optional argument is explicit at the call site.

Using *args and **kwargs Together

You can mix regular parameters, *args, keyword-only parameters, and **kwargs in one definition. The order matters.

python
1def demo(a, b, *args, verbose=False, **kwargs):
2    print("a =", a)
3    print("b =", b)
4    print("args =", args)
5    print("verbose =", verbose)
6    print("kwargs =", kwargs)
7
8
9demo(1, 2, 3, 4, verbose=True, mode="fast", retry=2)

The usual order is:

  • normal positional parameters
  • '*args'
  • keyword-only parameters
  • '**kwargs'

If you put them in the wrong order, Python raises a syntax error.

Unpacking in Function Calls

The same symbols are also used when calling a function.

* unpacks an iterable into positional arguments:

python
1def multiply(x, y, z):
2    return x * y * z
3
4
5values = [2, 3, 4]
6print(multiply(*values))

** unpacks a mapping into keyword arguments:

python
1def greet(name, language):
2    return f"{language}: hello, {name}"
3
4
5options = {"name": "Mina", "language": "English"}
6print(greet(**options))

This is especially helpful when arguments already live inside a tuple, list, or dictionary.

Why These Features Matter

These operators make Python APIs flexible without requiring dozens of overloads. Libraries use them to build decorators, wrappers, command dispatchers, serializers, and configuration layers.

They also help preserve compatibility. A wrapper can accept *args and **kwargs, log the call, then forward everything to an underlying function without knowing every parameter in advance.

Common Pitfalls

One common mistake is confusing packing and unpacking. In a function definition, *args and **kwargs collect values. In a function call, * and ** expand values.

Another mistake is forgetting that *args is a tuple and **kwargs is a dictionary. If you treat them like a single scalar value, the code will behave incorrectly.

People also miss the meaning of a bare *. It does not collect arguments by itself; it only separates positional parameters from keyword-only ones.

Finally, unpacking only works when the shapes match the function signature. If you unpack a list with two items into a function that needs three positional arguments, Python raises TypeError.

Summary

  • '*args collects extra positional arguments into a tuple.'
  • '**kwargs collects extra keyword arguments into a dictionary.'
  • A bare * makes the following parameters keyword-only.
  • In function calls, * unpacks iterables and ** unpacks mappings.
  • These features are essential for writing flexible Python APIs and wrappers.

Course illustration
Course illustration

All Rights Reserved.