Function Arguments

Python · Lesson 24 of 56 7 min read Updated

In Functions you passed values to a function in a fixed order. Python gives you much more control than that. You can name arguments when you call, give parameters default values, accept any number of values, and force callers to pass some values by name.

These features make functions easier to call correctly. They also explain code you will read in real projects, where signatures such as def run(*args, **kwargs) appear everywhere.

Positional and keyword arguments

A positional argument is matched to a parameter by its position: the first value goes to the first parameter, and so on. A keyword argument is matched by name, written as name=value. With keyword arguments the order no longer matters, and the call explains itself.

PythonRun it yourself
def book_ticket(passenger, source, destination):
    print(f"{passenger}: {source} to {destination}")

book_ticket("Ananya", "Pune", "Jaipur")
book_ticket(destination="Kochi", passenger="Rohan", source="Lucknow")
book_ticket("Isha", destination="Rohtak", source="Delhi")
Output
Ananya: Pune to Jaipur
Rohan: Lucknow to Kochi
Isha: Delhi to Rohtak

You can mix both kinds, but positional arguments must come first. Writing book_ticket(passenger="Isha", "Delhi", "Rohtak") is a SyntaxError: positional argument follows keyword argument.

Default parameter values

A parameter can have a default value, written as name=value in the definition. If the caller leaves that argument out, the default is used.

PythonRun it yourself
def chai_order(cups, sugar=True, size="regular"):
    sweet = "with sugar" if sugar else "no sugar"
    return f"{cups} {size} chai, {sweet}"

print(chai_order(2))
print(chai_order(1, sugar=False))
print(chai_order(3, size="large"))
Output
2 regular chai, with sugar
1 regular chai, no sugar
3 large chai, with sugar

Parameters with defaults must come after parameters without defaults. def chai_order(sugar=True, cups): fails with "parameter without a default follows parameter with a default".

The mutable default trap

This is one of the most famous Python surprises. A default value is created once, when the def line runs, not every time the function is called. If the default is a mutable object such as a list or dictionary, every call shares the same object.

PythonRun it yourself
def add_item(item, basket=[]):
    basket.append(item)
    return basket

print(add_item("rice"))
print(add_item("dal"))
Output
['rice']
['rice', 'dal']

The second call should have returned only ['dal'], but the rice from the first call is still in the shared list. The fix is to use None as the default and create a fresh list inside the function:

PythonRun it yourself
def add_item(item, basket=None):
    if basket is None:
        basket = []
    basket.append(item)
    return basket

print(add_item("rice"))
print(add_item("dal"))
Output
['rice']
['dal']

Use this None pattern for any default that is a list, dictionary or set. Numbers, strings, True, False and None are immutable, so they are always safe defaults.

Any number of arguments: *args and **kwargs

Put a star before a parameter name, as in *prices, and that parameter collects all extra positional arguments into a tuple. By convention it is often called *args, but a meaningful name is better.

PythonRun it yourself
def total_bill(*prices):
    print("Received:", prices)
    return sum(prices)

print(total_bill(120, 45, 300))
print(total_bill())
Output
Received: (120, 45, 300)
465
Received: ()
0

Two stars, as in **details, collect all extra keyword arguments into a dictionary. The usual name is **kwargs (short for keyword arguments).

PythonRun it yourself
def make_profile(name, **details):
    print(name)
    for key, value in details.items():
        print(f"  {key}: {value}")

make_profile("Kabir", city="Pune", course="BCA", year=2)
Output
Kabir
  city: Pune
  course: BCA
  year: 2

Keyword-only and positional-only parameters

Sometimes a value is so easy to confuse that callers should always name it. Any parameter after a bare * is keyword-only: it can only be passed as name=value.

The opposite also exists. Parameters before a / are positional-only: callers cannot use their names. This is useful when the names are not meaningful or may change later. Many built-in functions work this way; for example len() does not accept len(obj="Pune").

PythonRun it yourself
def transfer(amount, /, to_account, *, note=""):
    print(f"Sending ₹{amount} to {to_account} {note}".strip())

transfer(500, "SBI-1234")
transfer(2000, to_account="HDFC-5678", note="(rent)")

try:
    transfer(500, "SBI-1234", "gift")
except TypeError as error:
    print("Error:", error)
Output
Sending ₹500 to SBI-1234
Sending ₹2000 to HDFC-5678 (rent)
Error: transfer() takes 2 positional arguments but 3 were given

Here amount must be positional, to_account can be either, and note must be named. The try/except lets the program show the error instead of stopping; you will learn it in Errors & Exceptions.

When you combine everything, the order inside the brackets is always the same:

PartExampleHow callers pass it
Positional-onlya, b, /By position only
Normalc, d=0By position or by name
Extra positional*args (or a bare *)Collected into a tuple
Keyword-onlye, f=1By name only
Extra keyword**kwargsCollected into a dict

Unpacking arguments in a call

Stars also work the other way round. In a call, * spreads a list or tuple into separate positional arguments, and ** spreads a dictionary into keyword arguments.

PythonRun it yourself
def book_ticket(passenger, source, destination):
    print(f"{passenger}: {source} to {destination}")

trip = ["Meera", "Kochi", "Chennai"]
book_ticket(*trip)

details = {"passenger": "Farhan", "source": "Lucknow", "destination": "Agra"}
book_ticket(**details)
Output
Meera: Kochi to Chennai
Farhan: Lucknow to Agra

Common mistakes

  • A list or dict as a default value. It is shared between calls. Use None and create the object inside the function.
  • Passing the same argument twice. book_ticket("Isha", passenger="Riya", ...) raises TypeError: ... got multiple values for argument 'passenger'.
  • Misspelling a keyword. chai_order(2, suger=False) raises TypeError because there is no parameter called suger.
  • Thinking *args is a list. It is a tuple, so you cannot append() to it. Convert it with list(args) if you need to change it.

Key points

  • Positional arguments match by order; keyword arguments match by name and must come after positional ones.
  • Default values are used when an argument is left out, and must follow parameters without defaults.
  • Never use a mutable object such as [] or {} as a default; use None instead.
  • *args collects extra positional arguments into a tuple; **kwargs collects extra keyword arguments into a dict.
  • Parameters after * are keyword-only; parameters before / are positional-only.
  • In a call, *sequence and **dictionary unpack values into arguments.

Exercise

Write a function make_receipt(customer, *amounts, discount=0) for a shop in Rohtak. It should add up all the amounts, subtract discount percent, and return a string such as Aarav: 3 items, total ₹612.00. Make discount keyword-only (the *amounts parameter already does this). Test it with make_receipt("Aarav", 250, 180, 250, discount=10) and with a customer who buys nothing.

Show solution
Python
def make_receipt(customer, *amounts, discount=0):
    subtotal = sum(amounts)
    total = subtotal - subtotal * discount / 100
    return f"{customer}: {len(amounts)} items, total ₹{total:.2f}"

print(make_receipt("Aarav", 250, 180, 250, discount=10))
print(make_receipt("Priya"))
Output
Aarav: 3 items, total ₹612.00
Priya: 0 items, total ₹0.00

Because discount comes after *amounts, it can only be given by name, so a caller can never confuse it with a price.

Quick Quiz

1. What does def f(items=[]) risk?

2. Inside def f(*args):, what type is args?

3. In def f(a, *, b):, how must b be passed?

4. What does / mean in def f(x, y, /, z):?

Learn Python with a mentor

Free lessons get you started. Our Python Programming training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call