Skip to content
wannacode

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))
Output
8.0

With three arguments it works. With two, the program stops:

Error
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
  1. def stores the function under the name print_header. The name points to it.
  2. A call: the name points to the first function, and it prints "Corner Shop".
  3. The second def makes a new function and points the same name at it. The first one is gone.
  4. The second call: "Center Shop".
  5. 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)
Answer

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))
Output
6.5
8.0

c=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"))
Output
['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"))
Output
['bread']
['milk']

Try it

Find the bug

The program does not start. Python stops with a SyntaxError before it runs a single line. Which line is the bug on?

Pick the line with the bug.

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")
Output
Maria, nights: 1
Ivan, nights: 3
Petya, nights: 1
with breakfast
Georgi, nights: 2

Petya 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:

Error
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 than book("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())
Output
11.0
9.99
0

The 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)
Output
(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))
Output
Bread Milk Coffee
8
More 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 with receipt(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

Exercise

One function instead of several

1. The largest. Write one function, largest(*numbers), that returns the largest of any number of numbers.

Calls
largest(3, 8)
largest(4, 9, 2)
largest(2.5, 1.5)
Output
8
9
2.5

2. Average grade. The function average(*grades) returns the average of any number of grades, and with no grades it returns 0.

Calls
average(5, 6, 4)
average(6, 5)
average()
Output
5.0
5.5
0

3. A receipt line. print_line(item, qty) prints "Coffee x 2". Make the quantity optional: without it, it is 1.

Calls
print_line("Coffee", 2)
print_line("Croissant")
Output
Coffee x 2
Croissant x 1

4. 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.

Calls
shipping_cost(62.0)
shipping_cost(30.0)
shipping_cost(30.0, free_from=25)
Output
0
4.99
0

Test

Check yourself

1. The file has def total(a, b): and below it def total(a, b, c):. What happens at total(2, 3)?
2. def total(a, b, c=0): What does total(2, 3) return?
3. How do you call def book(name, nights=1, breakfast=False): so that there is breakfast and the nights stay at 1?
4. What is prices inside def total(*prices):?
5. Which of these does Python NOT run?

Made by Ivo Gergov as part of Evo Tech's campaign for accessible programming education ·