Default values
Problem
Two items, three items
The till has to add up the prices of the items. Sometimes there are two, sometimes three. The function means the same thing either way: "add up". In Java and C# you do this with two methods that have one name and a different number of parameters. You try the same:
def total(a, b): return a + b
def total(a, b, c): return a + b + c
print(total(2.5, 4.0, 1.5))print(total(2.5, 4.0))8.0With three arguments it works. With two, the program stops:
TypeError: total() missing 1 required positional argument: 'c'Python says that total is missing c. So it calls the function with three parameters. Where did the first one go?
The idea
One name, one function
In Python, def is a statement like any other. It runs when the program reaches it, and it stores the function under a name. A second def with the same name stores a new function under that name, and the old one is lost. Whichever def comes last before the call decides which function runs.
That is why Python has no overloading: two functions with one name that differ in their parameters, as in Java and C#. Instead, one function can take a different number of arguments. You will see how in the next cards.
def print_header(): print("Corner Shop")
print_header()
def print_header(): print("Center Shop")
print_header()Step by step, in words
- def stores the function under the name print_header. The name points to it.
- A call: the name points to the first function, and it prints "Corner Shop".
- The second def makes a new function and points the same name at it. The first one is gone.
- The second call: "Center Shop".
- There is one name. The last def the program has reached decides which function is called.
Try it
Which function?
What will the program print?
def describe(x): print(f"whole: {x}")
def describe(x): print(f"decimal: {x}")
describe(5)describe(5.0)def describe has replaced the first, so both calls reach "decimal". Python does not pick a function by the type of the argument: 5 and 5.0 go into the same function.The idea
A default value
One function is enough for both two and three items. Give the third parameter a default value: it is used when the argument is not passed.
def total(a, b, c=0): return a + b + c
print(total(2.5, 4.0))print(total(2.5, 4.0, 1.5))6.58.0c=0 means: if the call has only two arguments, c is 0. If it has three, c is the third one.
In Python, you do not put spaces around the = of a default value: c=0. That is what the PEP 8 style guide says.
Parameters with a default value are written after the ones without. Arguments are matched to parameters by position, so the optional ones go at the end.
More precisely, if you are curious
The default value is worked out once, when Python reaches the def, not on every call. For numbers and text this does not matter. But a default list is the same list for all calls:
def add_item(item, cart=[]): cart.append(item) return cart
print(add_item("bread"))print(add_item("milk"))['bread']['bread', 'milk']The second call carries on the list of the first. That is why for a default list you write None and make the list inside the function:
def add_item(item, cart=None): if cart is None: cart = [] cart.append(item) return cart
print(add_item("bread"))print(add_item("milk"))['bread']['milk']Try it
Find the bug
SyntaxError before it runs a single line. Which line is the bug on?Pick the line with the bug.
nights=1) comes before the parameter without one (name). Python forbids this: "parameter without a default follows parameter with a default". The fix is def book(name, nights=1):.The idea
Keyword arguments
A hotel takes bookings. One night without breakfast is the most common, so both are defaults:
def book(name, nights=1, breakfast=False): print(f"{name}, nights: {nights}") if breakfast: print(" with breakfast")
book("Maria")book("Ivan", 3)book("Petya", breakfast=True)book(nights=2, name="Georgi")Maria, nights: 1Ivan, nights: 3Petya, nights: 1 with breakfastGeorgi, nights: 2Petya wants breakfast, but only one night. You do not have to write the nights: breakfast=True passes the argument by name, straight to the parameter breakfast. This is called a keyword argument. With names, the order does not matter: Georgi passes both arguments by name, in reverse order.
The name has to be exact. A misspelled name does not slip through quietly, it stops the program:
book("Maria", night=2)
TypeError: book() got an unexpected keyword argument 'night'More precisely, if you are curious
- After a keyword argument there cannot be an argument without a name:
book(name="Maria", 3)does not start ("positional argument follows keyword argument"). - Keyword arguments make a call clearer even when you skip nothing:
book("Ivan", nights=3)is easier to read thanbook("Ivan", 3).
The idea
As many arguments as you like
What if there are five items? Twenty? You do not write a parameter for each one. You say that the function takes any number of arguments:
def total(*prices): result = 0 for p in prices: result += p return result
print(total(1.5, 2.0, 3.5, 4.0))print(total(9.99))print(total())11.09.990The asterisk before the name (*prices) means: "pass as many values as you like". Inside the function they arrive as a tuple: a sequence like a list that cannot be changed. With no arguments it is empty.
def show(*prices): print(prices)
show(1.5, 2.0)(1.5, 2.0)That is also why print prints as many values as you give it: it is one function that takes any number of arguments.
print("Bread", "Milk", "Coffee")print(max(3, 8, 2))Bread Milk Coffee8More precisely, if you are curious
- There can be only one such parameter. The parameters after it can only be passed by name:
def receipt(*prices, currency="€")is called withreceipt(2.5, 4.0, currency="EUR"). - There is also
**options: it collects the keyword arguments into a dictionary. You will come across it in other people's code.
Try it
What is missing?
def total(prices):
result = 0
for p in prices:
result += p
return result*prices: the asterisk before the name collects all the arguments.Exercise
One function instead of several
1. The largest. Write one function, largest(*numbers), that returns the largest of any number of numbers.
largest(3, 8)largest(4, 9, 2)largest(2.5, 1.5)892.52. Average grade. The function average(*grades) returns the average of any number of grades, and with no grades it returns 0.
average(5, 6, 4)average(6, 5)average()5.05.503. A receipt line. print_line(item, qty) prints "Coffee x 2". Make the quantity optional: without it, it is 1.
print_line("Coffee", 2)print_line("Croissant")Coffee x 2Croissant x 14. Free delivery. shipping_cost(total, free_from=50) returns 0 if the order is at least the threshold, otherwise €4.99. The threshold is €50 unless another one is passed.
shipping_cost(62.0)shipping_cost(30.0)shipping_cost(30.0, free_from=25)04.990Test