Python, Concept by Concept › Functions
Exercises: Functions
Core work is Exercises 1–10. Exercises 11–28 are More Practice; Exercises 29–32 are optional Challenges. Define the named functions and try every worked sample call. Turtle exercises use working starter scripts in assets/.
For each number function, keep the exact name and parameters, return the promised value, and call the function with the shown inputs. The arrows show what each call must return. Add a short purpose comment and use meaningful local names. The calls supply every input.
Exercise 1: Garden Border
A garden planner needs a reusable perimeter calculator.
Specification: Define rectangle_perimeter(width, height). Return the distance around a rectangle: two widths plus two heights. The returned value must be a number, not printed text.
Worked sample calls:
rectangle_perimeter(8, 5) -> 26
rectangle_perimeter(12, 3) -> 30
rectangle_perimeter(7.5, 2) -> 19.0
Real program
The real program reads a width and height with input().
How this is checked: Checked by tests that run your function rectangle_perimeter.
Exercise 2: Repair the Ride-Cost Tool
A ride-cost tool displays its calculation but gives no value back to a caller. Then total = ticket_cost(5) + 2 fails with TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'.
The broken function is:
def ticket_cost(rides):
print(rides * 3)
total = ticket_cost(5) + 2
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
Specification: Define ticket_cost(rides) so it returns rides * 3 instead of printing inside the function. Then the caller can save or calculate with the result. This is the unit's one exercise about the print-versus-return trap.
Worked sample calls:
ticket_cost(4) -> 12
ticket_cost(7) -> 21
ticket_cost(5) + 2 -> 17
How this is checked: Checked by tests that run your function ticket_cost.
Exercise 3: Exact-Multiple Test
A robotics team needs to know whether a supply count can be divided into equal groups.
Specification: Define is_multiple(number, divisor). Return the boolean result of testing whether the remainder is 0. For this exercise, divisor is always a positive integer.
Worked sample calls:
is_multiple(42, 7) -> True
is_multiple(43, 7) -> False
is_multiple(18, 3) -> True
Real program
The real program reads a number and divisor with input().
How this is checked: Checked by tests that run your function is_multiple.
Exercise 4: Score Span
A judge wants the distance between the highest and lowest of three number scores.
Specification: Define score_span(a, b, c). Use max(a, b) once to get the larger of the first two numbers, compare that result with c using max again, and use min(a, b, c) for the smallest number. Return highest minus lowest.
Worked sample calls:
score_span(4, 11, 7) -> 7
score_span(9, 2, 13) -> 11
score_span(6, 6, 6) -> 0
Real program
The real program reads three scores with input().
How this is checked: Checked by tests that run your function score_span.
Exercise 5: Total through an Endpoint
A practice tracker needs the total of every day number from 1 through its final day.
Specification: Define sum_to_n(n) for a positive integer n. Start a local total at 0. Use for number in range(1, n + 1) and update the running total once per trip. Return the final integer. For this exercise, write the loop yourself instead of calling sum.
Worked sample calls:
sum_to_n(4) -> 10
sum_to_n(8) -> 36
sum_to_n(1) -> 1
Real program
The real program reads an endpoint with input().
How this is checked: Checked by tests that run your function sum_to_n.
Exercise 6: Fibonacci Signal
A signal generator labels its first values 0, 1, 1, 2, 3, 5, and so on.
Specification: Define fib(n) for an integer n >= 0. Start local names a = 0 and b = 1. Repeat exactly n times. Inside the loop, use these three separate statements in this order: nxt = a + b, a = b, and b = nxt. Return a.
Worked sample calls:
fib(2) -> 1
fib(5) -> 5
fib(9) -> 34
Real program
The real program reads a Fibonacci position with input().
How this is checked: Checked by tests that run your function fib.
Exercise 7: Turtle Polygon Tool
A badge maker needs a reusable hexagon outline. The working starter already defines draw_polygon(n, side) and calls it to draw a small gray square.
Specification: Open assets/ex7_polygon_tool.py. Keep the module-level import turtle, the function parameters n and side, local angle = 360 / n, and the loop. Change the pen color to "teal" and change the sample call to draw_polygon(6, 48). Add a purpose comment above the call. Keep exactly one turtle.done() at the end.
Worked sample call:
draw_polygon(6, 48) -> closed hexagon with 6 pen-down moves
Run it from this unit directory with:
assets/ex7_polygon_tool.py
Check yourself: a teal six-sided outline with side length 48, a 60-degree turn after every side, and ends where it started: yes.
Real program
The real program reads the number of sides, the side length, and the colour with input(), then draws the same picture.
How this is checked: You check this one yourself, against the list below. The turtle drawing is checked from the moves your program makes.
The site cannot check this one. Run your program, then tick each item below when your work does it.
Exercise 8: Triangle Picture
A badge maker wants a growing triangle returned as one piece of text.
Specification: Define draw_triangle(n) for positive n. Use one loop; on each trip make a row with "*" * i. Build one result string by adding rows with + "\n" between them. Return the picture without a final newline.
Worked sample calls:
draw_triangle(3) -> "*\n**\n***"
Real program
The real program reads the triangle height with input().
How this is checked: Checked by tests that run your function draw_triangle.
Exercise 9: Name Banner
A club sign needs a border that adjusts to its message.
Specification: Define banner(text). Set the border width to len(text) + 4; return three lines: stars, "* " + text + " *", then the same stars. Join lines with "\n"; leave no trailing spaces.
Worked sample calls:
banner("Hi") -> "******\n* Hi *\n******"
Real program
The real program reads the banner text with input().
How this is checked: Checked by tests that run your function banner.
Exercise 10: Least Common Multiple
A timer needs the first positive number shared by two cycles.
Specification: Define gcd(a, b) with Euclid's remainder loop, then define lcm(a, b) for positive integers. Call your gcd helper and return a * b // gcd(a, b).
Worked sample calls:
lcm(4, 6) -> 12
lcm(21, 6) -> 42
Real program
The real program reads two positive integers with input().
How this is checked: Checked by tests that run your function lcm.
Exercise 11: More Practice: Digital Root
A number puzzle repeatedly totals decimal digits until one digit remains.
Specification: Define digit_sum(n) using % 10 and // 10, then digital_root(n) for positive integers. Call digit_sum repeatedly while the result has at least two digits.
Worked sample calls:
digital_root(9875) -> 2
9875 -> 29 -> 11 -> 2
Real program
The real program reads a positive integer with input().
How this is checked: Checked by tests that run your functions digit_sum, digital_root.
Exercise 12: More Practice: Primes Below
A science table needs to count prime labels before an upper limit.
Specification: Define is_prime(n) with the Lesson 2 early return, then count_primes_below(limit). Loop over integers from 2 up to but excluding limit, call is_prime for each, and return the count.
Worked sample calls:
count_primes_below(100) -> 25
Real program
The real program reads an upper limit with input().
How this is checked: Checked by tests that run your function count_primes_below.
Exercise 13: More Practice: Roman Numeral
A clock maker labels numbers 1 through 39 with Roman symbols.
Specification: Define to_roman(n) for 1–39. Start an empty result and use while n > 0. Its body must be an if/elif chain testing n >= 10, n >= 9, n >= 5, n >= 4, then the remaining 1 case. Append X, IX, V, IV, or I, and subtract 10, 9, 5, 4, or 1 respectively. Return the built string.
Worked sample calls:
to_roman(38) -> "XXXVIII"
to_roman(14) -> "XIV"
Real program
The real program reads an integer from 1 to 39 with input().
How this is checked: Checked by tests that run your function to_roman.
Exercise 14: More Practice: Days in a Month
A calendar needs to handle February and shorter months.
Specification: Define is_leap(year) using the rule: divisible by 400, or divisible by 4 but not 100. Define days_in_month(month, year) for months 1–12. Call is_leap for February; use if/elif/else to choose 29 or 28, 30 for April/June/September/November, or 31 otherwise.
Worked sample calls:
days_in_month(2, 2000) -> 29
days_in_month(2, 2100) -> 28
days_in_month(4, 2023) -> 30
days_in_month(1, 2023) -> 31
Real program
The real program reads a month and year with input().
How this is checked: Checked by tests that run your function days_in_month.
Exercise 15: More Practice: Weekday Name
A planner numbers weekdays from 0 for Sunday to 6 for Saturday.
Specification: Define weekday_name(number) with an if/elif chain returning the weekday string for each number 0–6. Define day_of_week(day, first_weekday) to return (first_weekday + day - 1) % 7. A calendar can call weekday_name(day_of_week(...)).
Worked sample calls:
weekday_name(0) -> "Sunday"
weekday_name(1) -> "Monday"
weekday_name(2) -> "Tuesday"
weekday_name(3) -> "Wednesday"
weekday_name(4) -> "Thursday"
weekday_name(5) -> "Friday"
weekday_name(6) -> "Saturday"
day_of_week(15, 3) -> 3
Real program
The real program reads a day and first weekday with input().
How this is checked: Checked by tests that run your functions weekday_name, day_of_week.
Exercise 16: More Practice: Bar with a Default
A score display draws bars with a usual mark and an optional alternate mark.
Specification: Define bar(n, symbol="#"). Return symbol * n. The caller may omit symbol to use the default.
Worked sample calls:
bar(5) -> "#####"
bar(3, "=") -> "==="
Real program
The real program reads a bar length and a symbol line with input() (an empty line keeps the default #).
How this is checked: Checked by tests that run your function bar.
Exercise 17: More Practice: Fix the Scope Bug
Two functions try to share a local value, but the second cannot see it.
Specification: Read the broken code and its exact error. Repair it by making set_total() return 12 and show(total) take that value as a parameter. Call show(set_total()); it must print 12.
Broken code (do not run):
def set_total():
total = 12
def show():
print(total)
set_total()
show()
NameError: name 'total' is not defined
Worked sample calls:
show(set_total()) -> prints 12
How this is checked: Checked by tests that run your function set_total.
Exercise 18: More Practice: Fix the Missing Argument
An area helper is called without all the values it needs.
Specification: Read the broken code and exact error. Repair the call to print(area(5, 3)); keep the function definition.
Broken code (do not run):
def area(width, height):
return width * height
print(area(5))
TypeError: area() missing 1 required positional argument: 'height'
Worked sample calls:
area(5, 3) -> 15
print(area(5, 3)) -> prints 15
How this is checked: Checked by tests that run your function area.
Exercise 19: More Practice: Fix the Call Before Define
A call appears before Python has reached its function definition.
Specification: Read the broken code and exact error. Move the definition before the call so print(triple(4)) prints 12.
Broken code (do not run):
print(triple(4))
def triple(n):
return 3 * n
NameError: name 'triple' is not defined
Worked sample calls:
triple(4) -> 12
print(triple(4)) -> prints 12
How this is checked: Checked by tests that run your function triple.
Exercise 20: More Practice: Shadowed Parameter
An outside name and a parameter have the same spelling.
Specification: Predict the exact output before running the code. Explain why the parameter n is a new local name and the outside n stays 10.
Code to trace:
n = 10
def double(n):
n = n * 2
return n
print(double(3), n)
Worked sample calls:
print(double(3), n) -> 6 10
Starter (read-only)
# Write your prediction as a comment, then run the traced code to check it.How this is checked: Checked by comparing your prediction with what the program really prints.
Answer format: one line
Exercise 21: More Practice: Fresh Locals
A counter is created inside a function on each call.
Specification: Predict the exact output before running the code. Explain why count starts at zero on both calls.
Code to trace:
def tick():
count = 0
count = count + 1
return count
print(tick(), tick())
Worked sample calls:
print(tick(), tick()) -> 1 1
Starter (read-only)
# Write your prediction as a comment, then run the traced code to check it.How this is checked: Checked by comparing your prediction with what the program really prints.
Answer format: one line
Exercise 22: More Practice: Predict the Scope
A function assigns to x, then the caller prints its own x.
Specification: Predict the exact output before running the code. Explain which x the final print uses.
Code to trace:
x = 5
def change():
x = 99
change()
print(x)
Worked sample calls:
print(x) -> 5
Starter (read-only)
# Write your prediction as a comment, then run the traced code to check it.How this is checked: Checked by comparing your prediction with what the program really prints.
Answer format: a number
Exercise 23: More Practice: Two Totals
A local running total shares a name with an outside total.
Specification: Set the global total = 100. Define add_up(n) with its own local total = 0, add the integers 1 through n, and return that local total. Print the returned value beside the unchanged global total.
Worked sample calls:
add_up(3) -> 6
print(add_up(3), total) -> 6 100
Real program
The real program reads an endpoint with input().
How this is checked: Checked by tests that run your function add_up.
Exercise 24: More Practice: Rounded Fahrenheit
A weather board shows a whole-number Fahrenheit value.
Specification: Define celsius_to_f(c) and rounded_fahrenheit(c). The second function must call the first, then return round(...) of its result. Check the intermediate 69.8 before rounding 21 Celsius.
Worked sample calls:
celsius_to_f(21) -> 69.8
rounded_fahrenheit(21) -> 70
Real program
The real program reads a Celsius value with input().
How this is checked: Checked by tests that run your functions celsius_to_f, rounded_fahrenheit.
Exercise 25: More Practice: Distance Apart
Two number markers need their distance on a line.
Specification: Define distance_apart(a, b) and return abs(a - b).
Worked sample calls:
distance_apart(3, 11) -> 8
distance_apart(15, 4) -> 11
Real program
The real program reads two numbers with input().
How this is checked: Checked by tests that run your function distance_apart.
Exercise 26: More Practice: Clamp a Score
A display accepts scores only from 0 through 100.
Specification: Define clamp(score) and return min(max(score, 0), 100).
Worked sample calls:
clamp(120) -> 100
clamp(-5) -> 0
clamp(64) -> 64
Real program
The real program reads a score with input().
How this is checked: Checked by tests that run your function clamp.
Exercise 27: More Practice: Star Function
A stage badge uses a closed five-point star.
Specification: Complete assets/ex27_star_function.py. Keep import turtle and exactly one turtle.done() at the end. Define draw_star(size) with five trips of turtle.forward(size) then turtle.right(144). Call draw_star(80).
Worked sample calls:
draw_star(80) -> closed five-point star with 5 pen-down moves
Run it from this unit directory with:
assets/ex27_star_function.py
Real program
The real program reads the star size with input(), then draws the same picture.
How this is checked: You check this one yourself, against the list below. The turtle drawing is checked from the moves your program makes.
The site cannot check this one. Run your program, then tick each item below when your work does it.
Exercise 28: More Practice: Polygon Row
A mural repeats three hexagons in a row.
Specification: Complete assets/ex28_polygon_row.py. Define draw_polygon(sides, length) with angle = 360 / sides, a loop that moves forward and turns left, then define polygon_row() to call it three times for hexagons with 6 sides of length 30. After each hexagon, lift the pen and move forward 70 before lowering it. After all three, lift the pen and move backward 210 to the start. Keep the original heading and exactly one turtle.done() at the end.
Worked sample calls:
polygon_row() -> 3 closed hexagons, 18 pen-down moves, then returns to start
Run it from this unit directory with:
assets/ex28_polygon_row.py
Real program
The real program reads the number of sides, the side length, the number of polygons, and the travel distance with input(), then draws the same picture.
How this is checked: You check this one yourself, against the list below. The turtle drawing is checked from the moves your program makes.
The site cannot check this one. Run your program, then tick each item below when your work does it.
Exercise 29: Euclid's GCD Tool
A fraction helper needs the greatest number that divides two positive integers.
Specification: Define gcd(a, b). While b != 0, calculate remainder = a % b, then use separate assignments a = b and b = remainder. Return a after the loop.
Worked sample calls:
gcd(54, 24) -> 6
gcd(35, 15) -> 5
gcd(81, 27) -> 27
Real program
The real program reads two positive integers with input().
How this is checked: Checked by tests that run your function gcd.
Exercise 30: Prime Gate
A puzzle gate opens only for a prime-number key.
Specification: Define is_prime(n) for an integer n >= 2. Loop through possible divisors in range(2, n). Return False as soon as a divisor leaves remainder 0. Return True only after the loop finishes without finding a divisor.
Worked sample calls:
is_prime(17) -> True
is_prime(21) -> False
is_prime(2) -> True
Real program
The real program reads an integer to test with input().
How this is checked: Checked by tests that run your function is_prime.
Exercise 31: Month Calendar
A month view begins on a weekday numbered 0 for Sunday.
Specification: Define month_calendar(days, first_weekday) to RETURN one string. Start with Su Mo Tu We Th Fr Sa. Build one growing row string without lists. Start with blank cells (" ") before day 1. For each day, make cell = str(d), adding one leading space when d < 10. Separate cells with one space: row = cell when empty, otherwise row + " " + cell. Add the row and start a new one when (first_weekday + d - 1) % 7 == 6. Do not pad the final row. Use "\n" only between rows; no trailing spaces or newline.
Worked sample calls:
month_calendar(30, 3) -> "Su Mo Tu We Th Fr Sa\n 1 2 3 4\n 5 6 7 8 9 10 11\n12 13 14 15 16 17 18\n19 20 21 22 23 24 25\n26 27 28 29 30"
Real program
The real program reads a day count and first weekday with input().
How this is checked: Checked by tests that run your function month_calendar.
Exercise 32: Longest Collatz
A number puzzle asks which start below a limit takes the most Collatz steps.
Specification: Define collatz_steps(n): while n != 1, halve an even n with // 2 or change an odd n to 3 * n + 1, counting each step. Define longest_collatz_below(limit) to test starts 1 through limit - 1. Keep the start with the greatest step count; use strict > so a tie keeps the smaller, earlier start. Return that starting number.
Worked sample calls:
collatz_steps(18) -> 20
longest_collatz_below(20) -> 18
Real program
The real program reads an upper limit with input().
How this is checked: Checked by tests that run your functions collatz_steps, longest_collatz_below.