*args, **kwargs, and lambda

Accept any number of arguments and write tiny inline functions

Intermediate 10 min

In this lesson

Most functions take a fixed set of arguments, but some need to accept ‘however many you give me’. Python handles that with *args and **kwargs. You’ll also meet lambda, a way to write a tiny function inline. These show up constantly in real libraries, so reading them is a real skill.

Explain it like I’m 5

*args is a basket for extra unnamed things you hand the function; **kwargs is a basket for extra labelled things. A lambda is a sticky-note function — small enough to write on one line and use right away.

*args and **kwargs

A parameter written *args collects any extra positional arguments into a tuple. A parameter written **kwargs collects any extra keyword arguments into a dictionary. The names args and kwargs are just convention — the * and ** are what matter.

Example
def total(*numbers):
    return sum(numbers)

print(total(1, 2, 3))
print(total(10, 20))

def make_profile(name, **details):
    profile = {"name": name}
    profile.update(details)
    return profile

print(make_profile("Ada", role="engineer", city="London"))
Output
6
30
{'name': 'Ada', 'role': 'engineer', 'city': 'London'}
*numbers becomes a tuple; **details becomes a dict.

Unpacking with * and **

The same symbols work in reverse at the call site. * spreads a list (or tuple) into separate positional arguments, and ** spreads a dict into keyword arguments. This is how you pass a collection you already have into a function that expects separate values.

Example
def total(*numbers):
    return sum(numbers)

nums = [3, 1, 2]
print(total(*nums))        # same as total(3, 1, 2)

def greet(greeting, name):
    return f"{greeting}, {name}!"

options = {"greeting": "Hi", "name": "Bo"}
print(greet(**options))     # same as greet(greeting="Hi", name="Bo")
Output
6
Hi, Bo!
* spreads a list into arguments; ** spreads a dict.

Lambda: tiny inline functions

A lambda is a small anonymous function written in one line: lambda x: x * 2. It’s handy for short throwaway callbacks, most commonly as the key for sorting. When the logic grows beyond a line, a normal def with a clear name is easier to read.

Example
people = [("Ada", 36), ("Bo", 19), ("Cy", 28)]
people.sort(key=lambda person: person[1])   # sort by age
print(people)
Output
[('Bo', 19), ('Cy', 28), ('Ada', 36)]
A lambda gives sort() a quick 'which part to sort by' rule.

Common mistake: Thinking the names args and kwargs are magic

Why it happens:

They appear everywhere, so they look like keywords.

How to fix it:

It’s the * and ** that do the work; args and kwargs are just conventional names. *items and **options work exactly the same way.

Common mistake: Overusing lambda where def is clearer

Why it happens:

A lambda feels concise, so it gets stretched to hold real logic.

How to fix it:

If the function needs more than a simple expression — or you’d benefit from a descriptive name — write a normal def.

Common mistake: Mixing up positional and keyword order

Why it happens:

When packing and unpacking, it’s easy to put a keyword argument before a positional one.

How to fix it:

Positional arguments come first, then keyword arguments. In definitions, the order is regular parameters, then *args, then **kwargs.

What kind of value does *args collect inside a function?

What kind of value does **kwargs collect?

When is a lambda a poor choice?

Mini exercise (medium)

Write two flexible functions: build_sentence(*words) that joins any number of words with spaces and ends with a full stop (e.g. build_sentence("hi", "there")"hi there."), and create_user(username, **settings) that returns a dict of the username plus any extra keyword settings.

Do it here. Finish the code below and press Run to try your answer right in the browser — no setup needed.

def build_sentence(*words):
    # TODO: join the words with spaces and add a full stop
    return ""

def create_user(username, **settings):
    # TODO: return a dict with the username plus any extra settings
    return {}

print(build_sentence("learning", "python", "is", "fun"))
print(create_user("ada", theme="dark", notifications=True))

What to learn next

You learned to write flexible functions: *args for extra positional arguments, **kwargs for extra keyword arguments, the * and ** unpacking that mirrors them at the call site, and lambda for short inline functions. You wrote build_sentence(*words) and create_user(username, **settings) yourself.

That’s every core idea of the unit — now bring them together. The Unit 4 Project walks you through designing and building a small object model one class at a time. When you’re ready, continue to the project.