Advanced Functions
Args, kwargs, lambda and recursion.
Ava's friends loved the add tax function, and now they want more. A function that adds any number of prices. A function that accepts optional settings. A tiny function to sort plants by price, without a full definition. Python has tools for each of these, and we will meet them one by one.

- Any number of arguments
- Optional named settings
- Tiny throwaway functions
*args: any number of values
Put a star before a parameter name, and it collects all the extra positional arguments into a tuple. By convention it is called args. Now the same function adds two prices, or twenty. You can also do the reverse, and spread a list into arguments, by placing a star before it in the call.
def add_all(*args):
print(args)
return sum(args)
print(add_all(5, 10))
print(add_all(5, 10, 20, 40))
prices = [3, 4, 5]
print(add_all(*prices))(5, 10) 15 (5, 10, 20, 40) 75 (3, 4, 5) 12
**kwargs: named options
Two stars collect extra named arguments into a dictionary, conventionally called kwargs. This is how flexible tools accept many optional settings. And you can spread a dictionary into named arguments, by placing two stars before it, in the call.
def order(item, **kwargs):
print(item, kwargs)
order("fern")
order("rose", color="red", gift=True)
opts = {"size": "large", "gift": False}
order("ivy", **opts)fern {}
rose {'color': 'red', 'gift': True}
ivy {'size': 'large', 'gift': False}Lambda: tiny functions
A lambda is a small unnamed function, written on one line. The word lambda, then parameters, a colon, and the result. They shine as short helpers. Here, Ava sorts plants by price, by passing a lambda as the key. The key function tells sort what to compare.
plants = [("fern", 9.5), ("rose", 11.0), ("ivy", 7.0)]
square = lambda x: x * x
print(square(6))
plants.sort(key=lambda p: p[1])
print(plants)
cheap = sorted(plants, key=lambda p: p[1])[0]
print(cheap)36
[('ivy', 7.0), ('fern', 9.5), ('rose', 11.0)]
('ivy', 7.0)Functions are values
In Python, functions are objects, just like numbers. You can store them in variables, put them in lists, and pass them to other functions. Here, a function takes another function and applies it to every price. Map and filter are built in versions of this idea.
def apply(fn, items):
return [fn(i) for i in items]
def cheaper(p):
return p - 1
print(apply(cheaper, [10, 20]))
print(list(map(lambda x: x * 2, [1, 2, 3])))
print(list(filter(lambda x: x > 1, [1, 2, 3])))[9, 19] [2, 4, 6] [2, 3]
Recursion: a function that calls itself
Recursion means a function calls itself, on a smaller problem. It needs a base case, where it stops, and a recursive case, where it calls itself. Here, we count down from three. And factorial multiplies a number by the factorial of the one below. Recursion suits trees and nested data, while loops suit simple repetition.
def countdown(n):
if n == 0:
print("Go!")
return
print(n)
countdown(n - 1)
def fact(n):
return 1 if n <= 1 else n * fact(n - 1)
countdown(3)
print(fact(5))3 2 1 Go! 120
A flexible total
Your turn. Write a function that accepts any number of prices, and an optional discount named percent, which defaults to zero. It returns the total after the discount. Ready? Here is one solution. Star args for the prices, a default for the percent, and a little maths.
Write total(*prices, percent=0) that returns the sum minus the percentage discount.
Show hint
*prices collects the values
Show solution
def total(*prices, percent=0):
s = sum(prices)
return s - s * percent / 100
print(total(10, 20, 30))
print(total(10, 20, 30, percent=10))60.0 54.0
Summary
Great progress. You can now accept any number of arguments with star args, collect named options with kwargs, write tiny lambdas, treat functions as values, and solve problems with recursion. Next, you will learn the most Pythonic trick of all, comprehensions.
Key takeaways- *args and **kwargs for flexibility
- lambda for small throwaway functions
- Recursion needs a base case