Python functions exercises solutions cheat sheet

Python functions exercises — consolidate what you know

Python functions exercises with solutions are where everything you’ve learned about functions gets tested for real. You’ve seen the theory and built three complete programs. Now it’s time to solve on your own.

In this article you’ll find four exercises across three levels, from a grade converter to a mini bank and a dice game. Each one uses functions in a real, meaningful way, not just as syntax practice.

As always: try to solve it, use the hint if you’ve been stuck for more than 10 minutes, and compare with the commented solution at the end. Use pythontutor.com to step through your solution and see how the function calls stack.

How to use this article

Read the exercise → try to solve it in VS Code → if stuck for more than 10 minutes read the hint → compare with the solution. Don’t jump to the solutions, you learn twice as much by solving it yourself first.

These Python functions exercises are ordered from least to most complex.


Python functions exercises Basic Level

Exercise 1 — Grade converter

Create a module of functions that converts grades between different scales. You need:

  • percentage_to_ten(grade) — converts a grade from 0-100 scale to 0-10 scale
  • ten_to_letter(grade) — converts a 0-10 grade to a letter grade (A: ≥9, B: ≥7, C: ≥5, F: <5)
  • ten_to_gpa(grade) — converts a 0-10 grade to GPA scale (0-4.0)
  • analyse_grade(grade_100) — calls all three functions and shows a complete report

The output should look like this:

Grade (0-100): 78

--- Complete grade analysis ---
Original (0-100):  78
Out of 10:         7.8
Letter grade:      B
GPA:               3.12

Message: Good work — keep pushing for that A

💡 Hint: ten_to_gpa converts using the ratio: round(grade_ten * 4 / 10, 2). For the message use if/elif/else based on the letter grade. analyse_grade should call all other functions — don’t recalculate inside it.


Exercise 2 — Text analyser

Create a set of functions to analyse a text string:

  • count_words(text) — returns the number of words
  • count_vowels(text) — returns the number of vowels (a, e, i, o, u — case insensitive)
  • count_sentences(text) — returns the number of sentences (count ., ! and ?)
  • most_frequent_word(text) — returns the word that appears most often (lowercase, ignore punctuation)
  • reading_time(text) — returns estimated reading time in seconds (average 200 words per minute)
  • full_analysis(text) — calls all the above and shows a complete report
Text to analyse: Python is great. Python is easy to learn. I love Python!

--- Text analysis ---
Words:            11
Vowels:           15
Sentences:        3
Most frequent:    python (3 times)
Reading time:     3 seconds

💡 Hint: For most_frequent_word use a dictionary to count occurrences — iterate through the words, strip punctuation with word.strip(".,!?") and count with counts[word] = counts.get(word, 0) + 1. Then find the key with the highest value using max(counts, key=counts.get).


Python functions exercises — Intermediate Level

Exercise 3 — Mini bank

Create a basic bank account simulator using functions. The account has a balance and a transaction history.

Functions needed:

  • create_account(owner, initial_balance) — returns a dictionary representing the account
  • deposit(account, amount) — adds to the balance, records the transaction, returns True/False
  • withdraw(account, amount) — subtracts from the balance if funds available, records it, returns True/False
  • get_balance(account) — returns the current balance
  • show_statement(account) — shows all transactions and the current balance
  • transfer(source, destination, amount) — calls withdraw on source and deposit on destination
--- Account: Sergio Medina ---
Opening balance: 1000.00 €

✓ Deposit: +500.00 € | Balance: 1500.00 €
✓ Withdrawal: -200.00 € | Balance: 1300.00 €
✗ Withdrawal rejected: insufficient funds (requested 2000.00 €, available 1300.00 €)
✓ Transfer to María: -300.00 € | Balance: 1000.00 €

--- Statement ---
  + 1000.00 € | Opening balance
  +  500.00 € | Deposit
  -  200.00 € | Withdrawal
  -  300.00 € | Transfer to María
─────────────────────────────
Current balance: 1000.00 €

💡 Hints:

  • Use a dictionary for the account: {"owner": name, "balance": balance, "transactions": []}
  • Each transaction in the list is a tuple: (type, amount, description)
  • transfer calls withdraw and only calls deposit if the withdrawal succeeded — check the return value
  • The classic mistake here: passing the account dictionary to the function works because dictionaries are mutable, the function modifies the original, not a copy

Python functions exercises — Final Challenge

Exercise 4 — Dice game

Create a complete two-player dice game using functions. Each player rolls two dice on their turn. The player with the higher total wins the round. Play a fixed number of rounds and show the final champion.

Special rules:

  • If both dice show the same number (doubles), score that number times 3 instead of adding
  • If a player rolls a total of 7, they lose that round automatically (seven out)
=== DICE GAME ===
Rounds to play: 3

--- Round 1 ---
Sergio rolls: 🎲 4 + 🎲 6 = 10
María rolls:  🎲 3 + 🎲 3 = DOUBLES! 3 × 3 = 9

Winner: Sergio (10 vs 9)

--- Round 2 ---
Sergio rolls: 🎲 3 + 🎲 4 = 7 — SEVEN OUT! 💀
María rolls:  🎲 5 + 🎲 2 = 7 — SEVEN OUT! 💀

Winner: Draw

--- Round 3 ---
Sergio rolls: 🎲 2 + 🎲 6 = 8
María rolls:  🎲 1 + 🎲 4 = 5

Winner: Sergio (8 vs 5)

=== FINAL RESULT ===
Sergio: 2 wins
María:  0 wins
Draws:  1

🏆 CHAMPION: Sergio!

💡 Hints:

  • roll_dice() returns a tuple of two random numbers: (random.randint(1,6), random.randint(1,6))
  • calculate_score(die1, die2) returns the score applying the special rules, doubles: die1 * 3, seven: 0 with a flag, normal: die1 + die2
  • play_round(player1, player2) calls roll_dice and calculate_score for each player, then determine_round_winner
  • Return a tuple from calculate_score: (score, is_seven_out, is_doubles)

Commented solutions

Solution Exercise 1:

# Grade converter

def percentage_to_ten(grade):
    return round(grade / 10, 1)

def ten_to_letter(grade):
    if grade >= 9:   return "A"
    elif grade >= 7: return "B"
    elif grade >= 5: return "C"
    else:            return "F"

def ten_to_gpa(grade):
    return round(grade * 4 / 10, 2)

def get_message(letter):
    messages = {
        "A": "Excellent work! Outstanding result",
        "B": "Good work — keep pushing for that A",
        "C": "Passed — there's room to improve",
        "F": "Not there yet — keep working at it"
    }
    return messages.get(letter, "")

def analyse_grade(grade_100):
    grade_ten = percentage_to_ten(grade_100)
    letter = ten_to_letter(grade_ten)
    gpa = ten_to_gpa(grade_ten)
    message = get_message(letter)

    print(f"\n--- Complete grade analysis ---")
    print(f"Original (0-100):  {grade_100}")
    print(f"Out of 10:         {grade_ten}")
    print(f"Letter grade:      {letter}")
    print(f"GPA:               {gpa}")
    print(f"\nMessage: {message}")

grade = float(input("Grade (0-100): "))
analyse_grade(grade)

Solution Exercise 2:

# Text analyser

def count_words(text):
    return len(text.split())

def count_vowels(text):
    vowels = "aeiouáéíóúAEIOUÁÉÍÓÚ"
    return sum(1 for c in text if c in vowels)

def count_sentences(text):
    return sum(1 for c in text if c in ".!?")

def most_frequent_word(text):
    words = text.lower().split()
    counts = {}
    for word in words:
        clean = word.strip(".,!?;:")
        if clean:
            counts[clean] = counts.get(clean, 0) + 1
    if not counts:
        return "none", 0
    word = max(counts, key=counts.get)
    return word, counts[word]

def reading_time(text):
    words = count_words(text)
    seconds = round(words / 200 * 60)
    return max(1, seconds)

def full_analysis(text):
    word, freq = most_frequent_word(text)
    print(f"\n--- Text analysis ---")
    print(f"Words:            {count_words(text)}")
    print(f"Vowels:           {count_vowels(text)}")
    print(f"Sentences:        {count_sentences(text)}")
    print(f"Most frequent:    {word} ({freq} times)")
    print(f"Reading time:     {reading_time(text)} seconds")

text = input("Text to analyse: ")
full_analysis(text)

Solution Exercise 3:

# Mini bank

def create_account(owner, initial_balance):
    account = {
        "owner": owner,
        "balance": initial_balance,
        "transactions": [("deposit", initial_balance, "Opening balance")]
    }
    return account

def deposit(account, amount, description="Deposit"):
    if amount <= 0:
        return False
    account["balance"] = round(account["balance"] + amount, 2)
    account["transactions"].append(("deposit", amount, description))
    print(f"✓ Deposit: +{amount:.2f} € | Balance: {account['balance']:.2f} €")
    return True

def withdraw(account, amount, description="Withdrawal"):
    if amount <= 0:
        return False
    if amount > account["balance"]:
        print(f"✗ Withdrawal rejected: insufficient funds "
              f"(requested {amount:.2f} €, available {account['balance']:.2f} €)")
        return False
    account["balance"] = round(account["balance"] - amount, 2)
    account["transactions"].append(("withdrawal", amount, description))
    print(f"✓ Withdrawal: -{amount:.2f} € | Balance: {account['balance']:.2f} €")
    return True

def get_balance(account):
    return account["balance"]

def transfer(source, destination, amount):
    desc_out = f"Transfer to {destination['owner']}"
    desc_in  = f"Transfer from {source['owner']}"
    if withdraw(source, amount, desc_out):
        deposit(destination, amount, desc_in)
        return True
    return False

def show_statement(account):
    print(f"\n--- Statement ---")
    for type_, amount, desc in account["transactions"]:
        symbol = "+" if type_ == "deposit" else "-"
        print(f"  {symbol} {amount:7.2f} € | {desc}")
    print("─" * 29)
    print(f"Current balance: {account['balance']:.2f} €")

# Usage
sergio = create_account("Sergio Medina", 1000)
maria  = create_account("María García", 500)

print(f"\n--- Account: {sergio['owner']} ---")
print(f"Opening balance: {sergio['balance']:.2f} €\n")

deposit(sergio, 500)
withdraw(sergio, 200)
withdraw(sergio, 2000)
transfer(sergio, maria, 300)

show_statement(sergio)

Solution Exercise 4:

# Dice game
import random

DICE_EMOJI = {1:"1️⃣", 2:"2️⃣", 3:"3️⃣", 4:"4️⃣", 5:"5️⃣", 6:"6️⃣"}

def roll_dice():
    return random.randint(1, 6), random.randint(1, 6)

def calculate_score(die1, die2):
    total = die1 + die2
    is_doubles = die1 == die2
    is_seven = total == 7

    if is_seven:
        return 0, True, False
    if is_doubles:
        return die1 * 3, False, True
    return total, False, False

def show_roll(player, die1, die2, score, is_seven, is_doubles):
    d1 = DICE_EMOJI[die1]
    d2 = DICE_EMOJI[die2]

    if is_seven:
        print(f"{player} rolls: {d1} + {d2} = 7 — SEVEN OUT! 💀")
    elif is_doubles:
        print(f"{player} rolls: {d1} + {d2} = DOUBLES! {die1} × 3 = {score}")
    else:
        print(f"{player} rolls: {d1} + {d2} = {score}")

def determine_round_winner(name1, score1, seven1, name2, score2, seven2):
    if seven1 and seven2:
        print("Winner: Draw")
        return "draw"
    if seven1:
        print(f"Winner: {name2} ({name2} wins by seven out)")
        return "p2"
    if seven2:
        print(f"Winner: {name1} ({name1} wins by seven out)")
        return "p1"
    if score1 > score2:
        print(f"Winner: {name1} ({score1} vs {score2})")
        return "p1"
    if score2 > score1:
        print(f"Winner: {name2} ({score2} vs {score1})")
        return "p2"
    print("Winner: Draw")
    return "draw"

def play_round(name1, name2):
    d1a, d1b = roll_dice()
    score1, seven1, doubles1 = calculate_score(d1a, d1b)
    show_roll(name1, d1a, d1b, score1, seven1, doubles1)

    d2a, d2b = roll_dice()
    score2, seven2, doubles2 = calculate_score(d2a, d2b)
    show_roll(name2, d2a, d2b, score2, seven2, doubles2)

    return determine_round_winner(name1, score1, seven1, name2, score2, seven2)

def show_final(name1, wins1, name2, wins2, draws):
    print(f"\n=== FINAL RESULT ===")
    print(f"{name1}: {wins1} win(s)")
    print(f"{name2}: {wins2} win(s)")
    print(f"Draws:  {draws}")

    if wins1 > wins2:
        print(f"\n🏆 CHAMPION: {name1}!")
    elif wins2 > wins1:
        print(f"\n🏆 CHAMPION: {name2}!")
    else:
        print("\n🤝 It's a tie!")

# Main game
print("=== DICE GAME ===")
name1 = input("Player 1 name: ")
name2 = input("Player 2 name: ")
rounds = int(input("Rounds to play: "))

wins1 = wins2 = draws = 0

for r in range(1, rounds + 1):
    print(f"\n--- Round {r} ---")
    result = play_round(name1, name2)
    if result == "p1":   wins1 += 1
    elif result == "p2": wins2 += 1
    else:                draws += 1

show_final(name1, wins1, name2, wins2, draws)

Cheat sheet — Python functions

# ============================================
# CHEAT SHEET — Python Functions
# Sergio Learns · sergiolearns.com
# ============================================

# DEFINE A FUNCTION
def function_name(param1, param2):
    code_block
    return value    # optional

# CALL A FUNCTION
result = function_name(arg1, arg2)
function_name(arg1, arg2)    # ignore return value

# NO PARAMETERS
def say_hello():
    print("Hello!")
say_hello()

# WITH PARAMETERS
def greet(name, age):
    print(f"Hello {name}, you are {age}")
greet("Sergio", 20)

# WITH RETURN
def square(n):
    return n * n
result = square(5)    # → 25

# MULTIPLE RETURN VALUES (tuple)
def min_max(numbers):
    return min(numbers), max(numbers)
minimum, maximum = min_max([3, 1, 7, 2])

# DEFAULT PARAMETERS
def power(base, exponent=2):    # default must come last
    return base ** exponent
power(5)        # → 25 (uses default)
power(5, 3)     # → 125 (overrides)

# FUNCTIONS CALLING FUNCTIONS
def average(grades):
    return sum(grades) / len(grades)

def classify(avg):
    return "Passed" if avg >= 5 else "Failed"

def analyse(grades):
    avg = average(grades)    # calls average
    cls = classify(avg)      # calls classify
    return avg, cls

# SCOPE — local variables
def my_func():
    x = 10    # only exists inside the function
print(x)      # NameError — x doesn't exist outside

# MUTABLE ARGUMENTS (dictionaries, lists)
def deposit(account, amount):
    account["balance"] += amount    # modifies the original

# COMMON ERRORS AND FIXES
# 1. Define ≠ call
def greet(): print("Hi")    # defines — doesn't run
greet()                     # calls — runs it

# 2. Missing return → None
def add(a, b):
    result = a + b    # missing return!
print(add(3, 4))     # → None, not 7

# 3. Counter inside function
count = 0
def increment():
    count += 1        # UnboundLocalError
# Fix: return the new value
def increment(c):
    return c + 1
count = increment(count)

# 4. Wrong argument order
def subtract(a, b): return a - b
subtract(10, 3)    # → 7
subtract(3, 10)    # → -7 (wrong order)

# GOOD FUNCTION DESIGN
# One function = one responsibility
# Name describes what it does (verb + noun)
# Parameters are inputs, return is output
# Don't use global variables inside functions

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *