Interview Q&A / Python

BeginnerIn-depth3 min readUpdated 2 Oct 2026

What are *args and **kwargs in Python?

SHORT ANSWER

In a function definition, *args collects any extra positional arguments into a tuple, and **kwargs collects any extra keyword arguments into a dict. They let a function accept a variable number of inputs. The same * and ** symbols also unpack a list or dict when calling a function.

Explain it simply

Imagine a college fest registration desk. Some students come alone, some bring three friends. The desk does not have a fixed number of chairs; it just says "all of you, sit in this row". *args is that row: however many positional values you pass, they are collected together.

**kwargs is like a form with optional fields. One student fills "college" and "phone", another fills only "email". Whatever named fields arrive are collected into a dictionary.

The names args and kwargs are only a convention. The stars do the work: *items or **options would behave the same way.

Example

python
def total_bill(*amounts, **extras):
    print(amounts)   # a tuple
    print(extras)    # a dict
    subtotal = sum(amounts)
    tip = extras.get("tip", 0)
    return subtotal + tip

print(total_bill(120, 80, 45))
# (120, 80, 45)
# {}
# 245

print(total_bill(200, 150, tip=30, coupon="FEST10"))
# (200, 150)
# {'tip': 30, 'coupon': 'FEST10'}
# 380

Unpacking at the call site works the other way round:

python
prices = [120, 80, 45]
options = {"tip": 20}
print(total_bill(*prices, **options))   # same as total_bill(120, 80, 45, tip=20) -> 265

How it works

Python matches arguments in a fixed order. In a definition, parameters go like this:

python
def f(a, b=2, *args, c, d=4, **kwargs):
    ...
  1. a, b: normal positional-or-keyword parameters.
  2. *args: any remaining positional values, as a tuple.
  3. c, d: keyword-only parameters, because they come after *args. They must be passed by name.
  4. **kwargs: any remaining named values, as a dict.

A bare * without a name (def f(a, *, c)) also makes the following parameters keyword-only, without collecting extras.

Real-world use

  • Wrappers and decorators: a decorator does not know the wrapped function's signature, so it accepts *args, **kwargs and passes them straight through.
  • Calling parent classes: super().__init__(*args, **kwargs) in Django models and forms.
  • Flexible helpers: a logging function that takes any number of values, like print itself.
  • Passing settings: building a dict of options and calling requests.get(url, **options).

Common mistakes

  • Putting **kwargs before *args in the definition. That is a syntax error; the order is fixed.
  • Forgetting that args is a tuple, so you cannot append to it.
  • Overusing them. If a function always needs name and age, list them explicitly. Clear signatures are easier to read and give better error messages.
  • Passing the same argument twice, like f(1, a=1), which raises TypeError: got multiple values for argument 'a'.

What to say in the interview

"*args lets a function take any number of extra positional arguments, which arrive as a tuple. **kwargs takes any number of extra keyword arguments, which arrive as a dict. The order in a definition is normal parameters, then *args, then keyword-only parameters, then **kwargs. I mostly use them in decorators and wrappers, where I need to accept whatever the wrapped function takes and pass it through unchanged. At the call site, * and ** do the reverse and unpack a list or dict into arguments."

Follow-up questions

  • What is a keyword-only argument, and how do you create one?
  • What does / mean in a function signature like def f(a, b, /, c)?
  • How would you write a decorator that works with any function?
  • Can you merge two dictionaries using **?

Go deeper

Read these once the basics above feel easy.

Since Python 3.8, a / in the parameter list marks everything before it as positional-only. For example, in def f(a, b, /, c), you cannot call f(a=1, b=2, c=3). Many built-ins work this way, such as len(obj).

** also works inside dict literals: {**defaults, **user_settings} merges two dicts, with later keys winning. Python 3.9 added the | operator for the same job: defaults | user_settings.

#python#functions#arguments

Related questions

Practise more Python questions

Test your recall with short answers, then return to the detailed explanations when you need context.

Open Python quick answers →

Get new questions like this by email

One short email when something new and useful lands. No spam, unsubscribe in one tap.

By subscribing you agree to the Privacy Policy.