Advertisement
⚙️ Functions

Python Function Parameters and Arguments – Complete Guide

Parameters are the variables listed in a function definition. Arguments are the actual values passed when calling the function. Python's parameter system is one of its most flexible features — supporting positional, keyword, default, variadic, and keyword-only parameters.

⏱️ 22 min read 🎯 Beginner 📅 Updated 2026

Positional Parameters

The most basic type. Arguments match parameters by position — first argument goes to first parameter, second to second, etc.

Python
def greet(first_name, last_name):
    print(f"Hello, {first_name} {last_name}!")

greet("Alice", "Smith")   # Alice → first_name, Smith → last_name
greet("Bob", "Jones")
▶ Output
Hello, Alice Smith! Hello, Bob Jones!

Default Parameter Values

Parameters can have default values — used when the caller doesn't provide that argument.

Python
def power(base, exponent=2):  # exponent defaults to 2
    return base ** exponent

print(power(5))       # 25 - uses default exponent=2
print(power(5, 3))    # 125 - overrides default
print(power(2, 10))   # 1024
▶ Output
25 125 1024
💡
Tip

Always put parameters with default values AFTER parameters without defaults, or you get a SyntaxError.

Advertisement

*args – Variable Positional Arguments

*args collects any number of positional arguments into a tuple.

Python
def sum_all(*numbers):  # numbers is a tuple
    print(f"Received: {numbers}")
    return sum(numbers)

print(sum_all(1, 2, 3))           # 6
print(sum_all(10, 20, 30, 40))    # 100
print(sum_all())                   # 0 - empty tuple
▶ Output
Received: (1, 2, 3) 6 Received: (10, 20, 30, 40) 100 Received: () 0

**kwargs – Variable Keyword Arguments

**kwargs collects any number of keyword arguments into a dictionary.

Python
def print_info(**details):  # details is a dict
    for key, value in details.items():
        print(f"  {key}: {value}")

print_info(name="Alice", age=25, city="London")
▶ Output
name: Alice age: 25 city: London

Parameter Order – The Golden Rule

When combining parameter types, order matters: regular → *args → keyword-only → **kwargs.

Python
# Full parameter order example
def full_function(a, b, c=10, *args, keyword_only=99, **kwargs):
    print(f"a={a}, b={b}, c={c}")
    print(f"args={args}")
    print(f"keyword_only={keyword_only}")
    print(f"kwargs={kwargs}")

full_function(1, 2, 3, 4, 5, keyword_only="hello", x=100)
▶ Output
a=1, b=2, c=3 args=(4, 5) keyword_only=hello kwargs={'x': 100}

The Mutable Default Argument Trap

This is one of the most famous Python gotchas, and it shows up in real code constantly. A default value is evaluated once, when the function is defined — not each time it's called. So a mutable default (list, dict, set) is shared across every call.

def add_item(item, basket=[]):   # ⚠️ default list created ONCE
    basket.append(item)
    return basket

print(add_item("apple"))   # ['apple']
print(add_item("bread"))   # ['apple', 'bread']  ← leftover from last call!

The fix is to default to None and build a fresh object inside the function:

def add_item(item, basket=None):
    if basket is None:
        basket = []          # new list every call
    basket.append(item)
    return basket

Parameter order rules

Python enforces a strict order when you mix parameter kinds. Break it and you get a SyntaxError.

OrderKindExample
1Positional / defaultdef f(a, b=2)
2*args (extra positionals)def f(a, *args)
3Keyword-only (after *)def f(a, *, key)
4**kwargs (extra keywords)def f(a, **kwargs)

Arguments are passed by object reference: rebinding a parameter inside the function doesn't affect the caller, but mutating a mutable argument does.

🏋️ Practical Exercise

Practice every parameter style:

  1. Write a greet(name, greeting="Hello") function using a default parameter.
  2. Write total(*numbers) that sums any number of positional arguments.
  3. Write describe(**info) that prints every keyword argument it receives.
  4. Call a function using keyword arguments out of order.

🔥 Challenge Exercise

Build a flexible make_report(title, *sections, author="Anon", **meta) function that prints a title, each section on its own line, the author, and any extra metadata key–value pairs. Call it several ways — with no sections, with many, and with extra metadata — to prove the parameter order rule (positional, *args, keyword-only, **kwargs) works. Bonus: add a keyword-only argument after *args.

📋 Summary

  • Parameters are the names in a definition; arguments are the values passed when calling.
  • Default values make parameters optional: def f(x, y=10).
  • *args collects extra positional arguments into a tuple; **kwargs collects extra keyword arguments into a dict.
  • The required order is: positional, *args, keyword-only, **kwargs.
  • Avoid mutable default arguments — they are created once and shared across calls; use None instead.
  • Keyword arguments can be passed in any order and improve call readability.

Interview Questions on Function Parameters

  • What is the difference between a parameter and an argument?
  • What is the difference between positional and keyword arguments?
  • What do *args and **kwargs do?
  • What is the correct order of parameters in a function definition?
  • Why is using a mutable default argument (like []) dangerous?
  • What are keyword-only arguments and how do you require them?
  • How do default parameter values work?

FAQ

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

*args captures extra positional arguments as a tuple; **kwargs captures extra keyword arguments as a dictionary. The names are convention — the * and ** are what matter.

Why shouldn’t I use a list as a default argument? +

Default values are evaluated once when the function is defined, so a mutable default like def f(items=[]) is shared across all calls and accumulates changes. Use def f(items=None) and create a new list inside the function.

What is the correct parameter order? +

Positional/required parameters first, then default parameters, then *args, then keyword-only parameters, then **kwargs. Violating this order is a syntax error.

How do I force callers to use keyword arguments? +

Place parameters after a bare * (or after *args). For example def f(a, *, b) makes b keyword-only, so it must be passed as b=value.