Difference Between *args and **kwargs in Python

The difference between *args and **kwargs in Python is what they collect. *args gathers any extra positional arguments into a tuple, while **kwargs gathers any extra keyword (name=value) arguments into a dictionary:

def demo(*args, **kwargs):
    print(args, kwargs)

demo(1, 2, color="red")   # (1, 2) {'color': 'red'}

Version check: Python 3.12.5, Windows Command Prompt. The output blocks are copied straight from those runs.

In this tutorial, we’ll cover each one alone, both together, unpacking into calls, decorators and the common errors.

What does *args do in a Python function?

Put a single star in front of a parameter name and Python packs every leftover positional argument into it. The name args is only a convention; the star is what matters. Here’s an order total that takes any number of prices:

def order_total(*prices):
    print("prices =", prices, "->", type(prices).__name__)
    return round(sum(prices), 2)

print(f"${order_total(19.99, 5.49, 3.75):.2f}")
print(f"${order_total(120.00):.2f}")
print(f"${order_total():.2f}")

Output:

prices = (19.99, 5.49, 3.75) -> tuple
$29.23
prices = (120.0,) -> tuple
$120.00
prices = () -> tuple
$0.00
Command Prompt output of a Python function using *args to collect prices into a tuple and sum them
Three prices, one price and no prices at all: prices is always a tuple, even when it’s empty.

You can loop over or index the tuple, but not change it. If you’re still getting comfortable with the def line, start with how to define a function in Python.

What does **kwargs do in a Python function?

Two stars collect every keyword argument that doesn’t match a named parameter, as a dict in the order you wrote them:

def make_profile(name, **details):
    print("details =", details, "->", type(details).__name__)
    profile = {"name": name}
    profile.update(details)
    return profile

print(make_profile("Megan Bowen", city="Seattle", state="WA", plan="Pro"))
print(make_profile("Alex Wilber"))

Output:

details = {'city': 'Seattle', 'state': 'WA', 'plan': 'Pro'} -> dict
{'name': 'Megan Bowen', 'city': 'Seattle', 'state': 'WA', 'plan': 'Pro'}
details = {} -> dict
{'name': 'Alex Wilber'}
Command Prompt output of a Python function using **kwargs to collect keyword arguments into a dictionary
The keyword arguments become a dict, and a call with no extras gets an empty dict instead of an error.

It’s a plain dict, so you can use any dict method on it. I merged it into the profile with update(); the Python dictionary update() method shows more ways to use it.

*args vs **kwargs: key differences at a glance

Feature*args**kwargs
CollectsExtra positional argumentsExtra keyword arguments
Type inside the functiontupledict
How callers pass valuesf(1, 2, 3)f(a=1, b=2)
Read values byIndex or loopKey, .get() or .items()
Empty when nothing extra is passed(){}

Neither one is a replacement for normal parameters with defaults. When you know the options in advance, name them; Python functions with optional arguments covers that approach.

How do you use *args and **kwargs together?

You can use both in one function, but the order is fixed: regular parameters, then *args, then keyword-only parameters, then **kwargs last. Anything after *items can only be passed by name:

def place_order(customer, *items, discount=0.0, **shipping):
    subtotal = sum(price for _, price in items)
    total = subtotal * (1 - discount)
    print(f"{customer}: {len(items)} items, total ${total:.2f}")
    print("  items:   ", items)
    print("  shipping:", shipping)

place_order("Adele Vance", ("Desk lamp", 34.99), ("Notebook", 6.50),
            discount=0.10, city="Austin", state="TX", ship_date="2026-11-03")

try:
    compile("def bad(**kwargs, *args):\n    pass\n", "orders.py", "exec")
except SyntaxError as err:
    print("SyntaxError:", err.msg)

Output:

Adele Vance: 2 items, total $37.34
  items:    (('Desk lamp', 34.99), ('Notebook', 6.5))
  shipping: {'city': 'Austin', 'state': 'TX', 'ship_date': '2026-11-03'}
SyntaxError: arguments cannot follow var-keyword argument
Command Prompt output of a Python function using *args and **kwargs together, plus the SyntaxError from the wrong order
The two items land in the tuple, the shipping fields in the dict, and putting **kwargs first is rejected before the code runs.

Command-line scripts follow a similar idea with flags and values, which using the Python main function with arguments walks through.

How do you unpack a list or dict into a function call with * and **?

At the call site the stars work in reverse: * spreads a list or tuple into positional arguments, and ** spreads a dict into keyword arguments:

def ship_label(name, city, state, zip_code):
    return f"{name}, {city}, {state} {zip_code}"

row = ["Lee Gu", "Denver", "CO", "80202"]
print(ship_label(*row))                       # list -> positional arguments

address = {"name": "Diego Siciliani", "city": "Boston", "state": "MA", "zip_code": "02134"}
print(ship_label(**address))                  # dict -> keyword arguments

defaults = {"plan": "Basic", "seats": 1, "billing": "monthly"}
print({**defaults, "seats": 5})               # ** also merges dicts

Output:

Lee Gu, Denver, CO 80202
Diego Siciliani, Boston, MA 02134
{'plan': 'Basic', 'seats': 5, 'billing': 'monthly'}

The dict keys must match the parameter names exactly, or you’ll get a TypeError. For more on the single-star version, see passing a tuple as an argument to a function in Python and unpacking a tuple in Python.

Pass *args and **kwargs through a decorator

The most common real-world use I see is a wrapper that accepts anything with *args, **kwargs and forwards it untouched:

import functools

def log_call(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print(f"{func.__name__} args={args} kwargs={kwargs}")
        return func(*args, **kwargs)      # pass everything through unchanged
    return wrapper

@log_call
def sales_tax(amount, rate=0.0825):
    return round(amount * rate, 2)

print(f"${sales_tax(250.00):.2f}")
print(f"${sales_tax(99.99, rate=0.06):.2f}")
print(f"${sales_tax(amount=40.00):.2f}")

Output:

sales_tax args=(250.0,) kwargs={}
$20.62
sales_tax args=(99.99,) kwargs={'rate': 0.06}
$6.00
sales_tax args=() kwargs={'amount': 40.0}
$3.30
Command Prompt output of a Python decorator that logs and forwards *args and **kwargs to a sales tax function
Each call prints what arrived as positional and keyword arguments, then returns the tax the real function calculated.

Decorators get their own deep dive in Python class decorators with examples. The same pass-through pattern shows up in subclasses that call super().__init__(*args, **kwargs), covered in Python class constructors with parameters.

Common *args and **kwargs errors and how to fix them

Most mistakes come down to an argument landing in the wrong place. You’ll likely meet these three TypeError messages:

def greet(name, **kwargs):
    return f"Hi {name}"

def order_total(*prices):
    return sum(prices)

def ship(city, state):
    return f"{city}, {state}"

for call in (lambda: greet("Megan", name="Alex"),
             lambda: order_total(prices=5),
             lambda: ship(*["Austin", "TX", "78701"])):
    try:
        call()
    except TypeError as err:
        print("TypeError:", err)

Output:

TypeError: greet() got multiple values for argument 'name'
TypeError: order_total() got an unexpected keyword argument 'prices'
TypeError: ship() takes 2 positional arguments but 3 were given
  • Multiple values: a keyword repeats a named parameter. Rename one.
  • Unexpected keyword: *args can’t take name=value. Pass by position.
  • Too many positional arguments: the unpacked list is too long. Slice it or add *args.

Once both stars feel natural, these function guides build on them:

Frequently asked questions

What is the difference between *args and **kwargs?

*args collects extra positional arguments into a tuple. **kwargs collects extra keyword arguments into a dictionary.

Do I have to name them args and kwargs?

No. The names are just conventions. *prices and **options work the same way; only the stars matter.

Which comes first, *args or **kwargs?

*args always comes before **kwargs, and **kwargs must be the last parameter. The reverse order is a SyntaxError.

Can a function have only **kwargs?

Yes. def f(**kwargs) accepts only keyword arguments, and calling it with a positional value raises a TypeError.

Is the order of **kwargs preserved?

Yes. Since Python 3.6, **kwargs keeps the order in which the caller wrote the keyword arguments.

Where are *args and **kwargs documented?

See arbitrary argument lists in the official Python tutorial.