*args, **kwargs & lambdas
Flexible parameters, argument unpacking, forwarding calls, lambdas, key functions, map and filter.
You already know how to define functions with fixed parameters. But what about print(), which accepts any number of values? Or a wrapper that forwards whatever arguments it receives to another function? This lesson covers Python's flexible argument syntax — *args and **kwargs — plus lambdas, tiny anonymous functions that shine when passing behaviour into other functions.
*args: any number of positional arguments#
A parameter prefixed with * collects all extra positional arguments into a tuple:
The name args is only a convention — *numbers is clearer here. You can combine regular parameters with *args; the regular ones are filled first:
**kwargs: any number of keyword arguments#
Two stars collect extra keyword arguments into a dict:
The full parameter order#
When you mix everything, the order is fixed:
- positional-only parameters (before
/) - normal parameters
*args- keyword-only parameters (anything after
*argsor a bare*) **kwargs
In practice you rarely need all five at once — but reading library signatures becomes much easier once you know them.
Unpacking at the call site#
The same symbols work in reverse when calling a function: * spreads an iterable into positional arguments, and ** spreads a dict into keyword arguments.
Unpacking is also handy for merging data: [*list_a, *list_b] and {**defaults, **overrides}.
Forwarding arguments#
The most important real-world use of *args, **kwargs is writing a function that wraps another and passes everything through unchanged. You'll use exactly this pattern when writing decorators:
Lambdas: small anonymous functions#
A lambda is a function written as a single expression, without a name or def:
The syntax is lambda parameters: expression. The expression's value is returned automatically; there's no return, and no statements such as loops or assignments are allowed.
PEP 8 recommends not assigning lambdas to names — use def for that, since it gives better tracebacks and room for a docstring. Lambdas are meant to be passed straight into another function.
Where lambdas shine: key= functions#
Many built-ins accept a key function that says what to compare: sorted, min, max, list.sort, itertools.groupby, and more.
Returning a tuple from the key sorts by several criteria at once; negating a number reverses its direction.
The operator module offers ready-made alternatives that are slightly faster and often clearer:
map() and filter()#
map(func, iterable) applies a function to every item; filter(func, iterable) keeps items where the function returns something truthy. Both return lazy iterators:
In modern Python, a comprehension is usually more readable than map/filter with a lambda: [n * n for n in nums] and [n for n in nums if n % 2 == 0]. That's the next lesson. functools.reduce also exists for folding a sequence into one value, but sum, max, min, any, all or a plain loop are usually clearer.
Worked example: a flexible HTML tag builder#
class is a Python keyword, so the example uses the common convention of a trailing underscore (class_) and strips it.
Common mistakes#
- Forgetting to unpack when forwarding:
func(args, kwargs)passes a tuple and a dict as two arguments. Writefunc(*args, **kwargs). - Overusing
*args/**kwargs: explicit parameters document themselves and let editors help you. Use the flexible forms when you genuinely need them. - Complex lambdas: if it needs a comment, make it a named
def. - Lambdas in loops capturing a loop variable — remember the late-binding gotcha from the scope lesson.
What's next#
Comprehensions came up twice in this lesson. Next you'll master them properly: list, dict and set comprehensions and generator expressions.
Check your understanding
Quick quiz
1.Inside
def f(*args, **kwargs), what type iskwargs?2.What does
f(*[1, 2, 3])do?3.Which statement about lambdas is true?
Finished reading?
Mark this lesson complete to track your progress.