*args, **kwargs, and lambda
Accept any number of arguments and write tiny inline functions
In this lesson
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.
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"))
6
30
{'name': 'Ada', 'role': 'engineer', 'city': 'London'}
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.
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")
6 Hi, Bo!
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.
people = [("Ada", 36), ("Bo", 19), ("Cy", 28)]
people.sort(key=lambda person: person[1]) # sort by age
print(people)
[('Bo', 19), ('Cy', 28), ('Ada', 36)]
Common mistake: Thinking the names args and kwargs are magic
They appear everywhere, so they look like keywords.
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
A lambda feels concise, so it gets stretched to hold real logic.
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
When packing and unpacking, it’s easy to put a keyword argument before a positional one.
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?
*args gathers the extra positional arguments into a tuple.
What kind of value does **kwargs collect?
**kwargs gathers the extra keyword arguments into a dict.
When is a lambda a poor choice?
Lambdas suit one-line expressions; longer logic reads better as a named def.
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))
In build_sentence, " ".join(words) + ".". In create_user, start a dict with the username, then .update(settings).
def build_sentence(*words):
return " ".join(words) + "."
def create_user(username, **settings):
user = {"username": username}
user.update(settings)
return user
print(build_sentence("learning", "python", "is", "fun"))
print(create_user("ada", theme="dark", notifications=True))
learning python is fun.
{'username': 'ada', 'theme': 'dark', 'notifications': True}
assert build_sentence("a", "b", "c") == "a b c.", "join the words with spaces and end with a full stop"
assert build_sentence("hi") == "hi.", "build_sentence should work for any number of words"
assert create_user("bo", role="admin") == {"username": "bo", "role": "admin"}, "create_user should keep the username plus any keyword settings"
print("✓ Flexible functions!")