Week 3 Tutorial: Functions
Quick reference
Defining and calling a function
def greet():
print("Hello")
greet()
- Use
defto define a function. - Put
:after)and indent the code inside the function. This code is the function body. - Defining a function does not run its body. Calling it runs the body.
- Python must run the function definition before you can call the function.
Parameters and arguments
def rectangle_area(width, height):
return width * height
area = rectangle_area(4, 3)
- Parameters are the names in the function definition:
widthandheight. - Arguments are the values you give to a function when you call it:
4and3. - Here, the order matters:
widthgets4, andheightgets3.
Returning a value
def double(number):
return number * 2
result = double(5)
print(result) # 10
print(double(5) + 3) # 13
returnends the function call and sends a value back to the code that called it.- You can store this value in a variable or use it in an expression.
print()shows a value on the screen. It does not return the value it shows.- If a function reaches its end without running
return, it returnsNone. returnon its own also returnsNone.
Decisions inside functions
def result_message(score):
if score >= 50:
return "Pass"
return "Try again"
The function ends as soon as a return runs. If your code needs a result, make sure the function returns one for every case.
Local variables
def add_one(number):
result = number + 1
return result
number = 10
answer = add_one(number)
print(number) # 10
print(answer) # 11
- Parameters and variables created inside these functions are local: their names belong to that function call.
- The
numberinside the function and thenumberoutside it are separate names. - Giving a new value to
numberinside the function does not changenumberoutside it. - Use
returnto send a result back to the code that called the function.
Pure functions
def total_minutes(hours, minutes):
return hours * 60 + minutes
A pure function always returns the same result when you give it the same arguments. It has no side effects: for example, it does not print output or change data outside the function.
Keep input and output separate from the calculation:
hours = int(input("Enter hours: "))
minutes = int(input("Enter minutes: "))
total = total_minutes(hours, minutes)
print(f"Total minutes: {total}")
Docstrings
def square(number):
"""Return the square of the given number."""
return number * number
A docstring explains what a function does. Write it as the first statement inside the function, between triple quotes (""").
Checks with assert
assert square(3) == 9
assert square(0) == 0
assert square(-2) == 4
assertchecks a condition.- If the condition is
True, the program continues without printing anything. - If it is
False, Python reports anAssertionError. - Check common values and values at a boundary, such as
49and50when the pass mark is50.
Decomposition
Decomposition means breaking a problem into smaller tasks. Give each task a name, such as:
- Read the input.
- Calculate the result.
- Print the result.
Give each function a clear task. Decide what arguments it needs and what value it should return.
Problem 1: Say hello
Write a function named greet with one parameter, name. The function should print a greeting using that name.
Call the function twice: once with "Aziza" and once with "Bekzod".
Expected output
Hello, Aziza!
Hello, Bekzod!
Problem 2: Age in months
Write a function named age_in_months with one parameter, years. The function should return the number of months in that many years.
Assume each year has 12 months.
Call the function with 18, 5, and 0. Print each returned value outside the function.
Expected output
216
60
0
Problem 3: Money left
Write a function named money_left with two parameters:
money: how much money you have;price: how much you spend.
The function should return how much money remains. Assume money and price are non-negative and you have enough money.
Use these calls and print each returned value outside the function:
money_left(50000, 18000)
money_left(20000, 20000)
money_left(10000, 0)
Expected output
32000
0
10000
Problem 4: Bus fare
Write a function named bus_fare with one parameter, age.
The function should return:
0if the passenger is younger than7;2000otherwise.
Assume age is a non-negative integer.
Use these calls and print each returned value outside the function:
bus_fare(4)
bus_fare(7)
bus_fare(18)
Expected output
0
2000
2000
Problem 5: In range
Write a function named is_in_range with three parameters: number, lower, and upper.
The function should return True if number is between lower and upper, including both ends. Otherwise, return False.
Assume lower is less than or equal to upper.
Check your function using these assertions:
assert is_in_range(5, 1, 10) == True
assert is_in_range(1, 1, 10) == True
assert is_in_range(10, 1, 10) == True
assert is_in_range(0, 1, 10) == False
assert is_in_range(11, 1, 10) == False
Problem 6: Alarm message
Write a function named alarm_message with two parameters:
hour: a whole number from0to23;is_weekend: eitherTrueorFalse.
The function should return:
"Sleep in"if it is the weekend, whatever the hour;"Get up"if it is not the weekend and the hour is7or later;"Too early"otherwise.
Add a short docstring and check your function using these assertions:
assert alarm_message(6, False) == "Too early"
assert alarm_message(7, False) == "Get up"
assert alarm_message(9, False) == "Get up"
assert alarm_message(6, True) == "Sleep in"
assert alarm_message(9, True) == "Sleep in"
Problem 7: Cinema tickets
A cinema uses these ticket prices:
- children younger than
12:20000so‘m; - everyone aged
12or older:35000so‘m.
Write two functions:
ticket_price(age)— return the ticket price for one person.total_price(first_age, second_age)— callticket_pricefor each person and return the total price.
Assume both ages are non-negative integers. Add a short docstring to each function.
Check your functions:
assert ticket_price(11) == 20000
assert ticket_price(12) == 35000
assert total_price(8, 10) == 40000
assert total_price(8, 20) == 55000
assert total_price(20, 8) == 55000
assert total_price(18, 25) == 70000
Then write a program that reads two ages and prints the total price. Keep input() and print() outside both functions.
Example
Enter the first age: 8
Enter the second age: 20
Total price: 55000 so‘m
Problem 8: Parking fee
A car park charges for each hour started. For example, 61 minutes counts as 2 hours.
The prices are:
0minutes: no charge;- the first hour:
5000so‘m; - each additional hour:
3000so‘m.
Write two functions:
hours_to_pay(minutes)— return the number of hours to pay for. Use//and%to count full hours and check for remaining minutes.parking_fee(minutes)— usehours_to_payand return the total fee.
Assume minutes is a non-negative integer. Add a short docstring to each function.
Check your functions:
assert hours_to_pay(0) == 0
assert hours_to_pay(60) == 1
assert hours_to_pay(61) == 2
assert parking_fee(0) == 0
assert parking_fee(1) == 5000
assert parking_fee(60) == 5000
assert parking_fee(61) == 8000
assert parking_fee(125) == 11000
Then read the number of minutes from the user and print the fee. Keep input() and print() outside both functions.
Example
Enter parking time in minutes: 125
Parking fee: 11000 so‘m
Problem 9: Is this date valid?
Write a program that checks whether a day, month, and year form a valid date.
Write three functions:
is_leap_year(year)— returnTrueif the year is a leap year, orFalseotherwise.days_in_month(month, year)— useis_leap_yearwhen needed and return the number of days in the month. Assume the month is from1to12.is_valid_date(day, month, year)— returnTrueif the date is valid, orFalseotherwise. Usedays_in_month, but only after checking the year and month.
A valid date must have:
- a year greater than
0; - a month from
1to12; - a day from
1to the number of days in that month.
The month lengths are:
- 30 days: April (
4), June (6), September (9), November (11); - 31 days: all other months except February;
- February (
2):29days in a leap year, otherwise28.
A year is a leap year if it is divisible by 400, or if it is divisible by 4 but not by 100.
Check your functions:
assert is_leap_year(2000) == True
assert is_leap_year(1900) == False
assert days_in_month(2, 2024) == 29
assert days_in_month(4, 2026) == 30
assert is_valid_date(29, 2, 2024) == True
assert is_valid_date(29, 2, 2026) == False
assert is_valid_date(31, 4, 2026) == False
assert is_valid_date(0, 1, 2026) == False
assert is_valid_date(15, 13, 2026) == False
assert is_valid_date(1, 1, 0) == False
Then read a day, month, and year from the user and print Valid date or Invalid date. Assume the user enters integers.
Example
Enter the day: 29
Enter the month: 2
Enter the year: 2026
Invalid date
Problem 10: Time for a meeting
Two students want to work together. Each student has a free period during the same day.
Times are given as minutes after midnight. For example, 540 means 09:00, and 600 means 10:00.
Write two functions:
overlap_minutes(start1, end1, start2, end2)— return the number of minutes when both students are free. Return0if their free periods do not overlap.can_meet(start1, end1, start2, end2, duration)— useoverlap_minutesand return whether they have enough shared time for a meeting ofdurationminutes.
Assume:
- all times are integers from
0to1440; - each start time is earlier than its end time;
durationis a positive integer.
If one free period ends exactly when the other starts, they have 0 shared minutes.
Example
The first student is free from 09:00 to 11:00. The second is free from 10:00 to 12:00.
They are both free from 10:00 to 11:00: 60 minutes.
Checks
# Partly overlapping periods
assert overlap_minutes(540, 660, 600, 720) == 60
# One period is inside the other
assert overlap_minutes(540, 720, 600, 660) == 60
# Same periods
assert overlap_minutes(540, 600, 540, 600) == 60
# Periods that touch or are separate
assert overlap_minutes(540, 600, 600, 660) == 0
assert overlap_minutes(540, 600, 660, 720) == 0
# The second student is free earlier
assert overlap_minutes(600, 720, 540, 660) == 60
assert can_meet(540, 660, 600, 720, 60) == True
assert can_meet(540, 660, 600, 720, 61) == False
Add two more assertions of your own: one where can_meet returns True and one where it returns False.
Problem 11: Packing an order
A shop packs cups into two sizes of boxes:
- a large box holds exactly
6cups; - a small box holds exactly
4cups.
Every box used must be full. The shop has a limited number of each size. You do not have to use all available boxes.
Write two functions:
minimum_boxes(cups, large_available, small_available)— return the smallest number of boxes needed to pack exactlycupscups. Return-1if this is impossible.can_pack(cups, large_available, small_available)— useminimum_boxesand returnTrueif the order can be packed, orFalseotherwise.
Assume all arguments are non-negative integers. Packing 0 cups needs 0 boxes.
Example
An order contains 18 cups. The shop has 2 large boxes and 3 small boxes.
Using both large boxes leaves 6 cups, which cannot fill small boxes exactly. Using 1 large box and 3 small boxes packs all 18 cups.
The result is 4 boxes.
Checks
assert minimum_boxes(18, 3, 0) == 3
assert minimum_boxes(18, 2, 3) == 4
assert minimum_boxes(20, 2, 2) == 4
assert minimum_boxes(8, 2, 0) == -1
assert minimum_boxes(8, 0, 2) == 2
assert minimum_boxes(7, 5, 5) == -1
assert minimum_boxes(0, 0, 0) == 0
assert can_pack(18, 2, 3) == True
assert can_pack(8, 2, 0) == False
Add two more assertions of your own.
Problem 12: Split the bill
Three friends share a restaurant bill equally. Each friend has a limited amount of money.
If a friend cannot pay their share, they pay all the money they have. The other two split the remaining amount equally. If one of them cannot pay that new share, the last friend pays what remains.
For example, the bill is 90000 so‘m:
- Aziza has
10000so‘m. - Bekzod has
50000so‘m. - Dilshod has
100000so‘m.
Each person’s first share is 30000. Aziza can pay only 10000, so Bekzod and Dilshod each pay 40000.
Write a function named payment_for_first with four parameters:
bill: the total bill;first_money: the first friend’s available money;second_money: the second friend’s available money;third_money: the third friend’s available money.
The function should return how much the first friend pays. Return -1 if the three friends do not have enough money in total.
Assume all arguments are non-negative numbers. Use ordinary division; you do not need to round the results.
Divide your solution into smaller functions where useful.
Checks
# Everyone can pay an equal share
assert payment_for_first(90000, 50000, 50000, 50000) == 30000
# The first friend cannot pay an equal share
assert payment_for_first(90000, 10000, 50000, 100000) == 10000
# Another friend cannot pay an equal share
assert payment_for_first(90000, 50000, 10000, 100000) == 40000
# Two friends have too little money
assert payment_for_first(90000, 100000, 10000, 20000) == 60000
# Not enough money in total
assert payment_for_first(90000, 20000, 20000, 20000) == -1
# No bill to pay
assert payment_for_first(0, 10000, 20000, 30000) == 0
Add a check where one friend can afford the first equal share but cannot afford the larger share after another friend pays less.
Problem 13: Pouring water
You have three bottles: A, B, and C. Each bottle has a capacity and a starting amount of water, measured in millilitres.
Pour water in this order:
- From A into B.
- From B into C.
- From C into A.
At each step, pour as much as possible. Stop when the source bottle is empty or the receiving bottle is full. No water is spilled.
Write two functions:
pour_amount(source_water, destination_water, destination_capacity)— return how much water can be poured.water_in_a(capacity_a, capacity_b, capacity_c, water_a, water_b, water_c)— usepour_amountfor each step and return the amount of water in A after all three steps.
Each step must use the amounts left after the previous step.
Assume all arguments are integers, capacities are positive, and each starting amount is between 0 and that bottle’s capacity.
Example
The capacities are:
- A:
800ml; - B:
500ml; - C:
300ml.
At the start, A contains 800 ml, and B and C are empty.
| Step | Water in A | Water in B | Water in C |
|---|---|---|---|
| Start | 800 | 0 | 0 |
| A → B | 300 | 500 | 0 |
| B → C | 300 | 200 | 300 |
| C → A | 600 | 200 | 0 |
The function returns 600.
Checks
# The source can be emptied
assert pour_amount(200, 100, 500) == 200
# The receiving bottle fills first
assert pour_amount(600, 100, 500) == 400
# The receiving bottle is already full
assert pour_amount(200, 500, 500) == 0
assert water_in_a(800, 500, 300, 800, 0, 0) == 600
assert water_in_a(500, 800, 300, 500, 0, 0) == 300
# All bottles start full
assert water_in_a(800, 500, 300, 800, 500, 300) == 800
# All bottles start empty
assert water_in_a(800, 500, 300, 0, 0, 0) == 0
Add a check where all three bottles start partly full. Trace the three pours to find the expected answer before running your code.