Python Coding Challenges

This self-check practice test covers core Python 3 fundamentals: syntax, data types, control flow, functions, strings, lists, dictionaries, sets, comprehensions, and common algorithms. Work through Section A (multiple choice / predict-the-output) and Section B (coding challenges) on your own first. Each item is numbered so you can verify your work against the matching entry in the Answer Key & Solutions section at the bottom of the page. All snippets and solutions run correctly on Python 3.

Python code on a screen

Section A: Multiple Choice / Predict the Output

Read each snippet carefully and choose the correct result or concept. Answers A1–A10 are in the answer key.

A1. List mutability and aliasing

a = [1, 2, 3]
b = a
b.append(4)
print(a)

What does this print?

Options:

(a) [1, 2, 3]   (b) [1, 2, 3, 4]   (c) [4]   (d) Error

A2. Slicing

s = "python"
print(s[1:4])

What is printed?

Options:

(a) "pyth"   (b) "yth"   (c) "ytho"   (d) "yt"

A3. Negative-step slicing

s = "python"
print(s[::-1])

What is printed?

Options:

(a) "python"   (b) "nohtyp"   (c) ""   (d) Error

A4. Mutable default argument pitfall

def add(x, items=[]):
    items.append(x)
    return items

print(add(1))
print(add(2))

What is printed across the two calls?

Options:

(a) [1] then [2]   (b) [1] then [1, 2]   (c) [1, 2] then [1, 2]   (d) Error

A5. Truthiness

print(bool([]), bool([0]), bool(0), bool("0"))

What is printed?

Options:

(a) False True False True   (b) True True False False   (c) False False False False   (d) False True False False

A6. Integer vs. true division

print(7 // 2, 7 / 2, 7 % 2)

What is printed?

Options:

(a) 3 3.5 1   (b) 3.5 3.5 1   (c) 3 3 1   (d) 4 3.5 1

A7. dict.get with a default

d = {"a": 1}
print(d.get("b", 0))

What is printed?

Options:

(a) None   (b) 0   (c) KeyError   (d) 1

A8. Set comprehension and uniqueness

nums = [1, 2, 2, 3, 3, 3]
print(len({x for x in nums}))

What is printed?

Options:

(a) 6   (b) 3   (c) 1   (d) Error

A9. Comprehension building a dict

print({x: x * x for x in range(3)})

What is printed?

Options:

(a) {0: 0, 1: 1, 2: 4}   (b) {1: 1, 2: 4, 3: 9}   (c) [0, 1, 4]   (d) {0, 1, 4}

A10. Exception handling flow

try:
    x = int("abc")
except ValueError:
    x = -1
print(x)

What is printed?

Options:

(a) 0   (b) -1   (c) "abc"   (d) The program crashes

Section B: Coding Challenges

Eight problems of increasing difficulty. Write your own solution first, then check against B1–B8 in the answer key.

1

FizzBuzz

Print the numbers from 1 to n. For multiples of 3 print "Fizz", for multiples of 5 print "Buzz", and for multiples of both print "FizzBuzz".

Example:

Input:  n = 15
Output: 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz
2

Reverse the words in a sentence

Given a sentence, return a new string with the order of the words reversed. Collapse runs of whitespace to single spaces.

Example:

Input:  "the quick brown fox"
Output: "fox brown quick the"
3

Count word frequency with a dict

Given a string of words, return a dictionary mapping each word (case-insensitive) to the number of times it appears.

Example:

Input:  "the cat the dog the bird"
Output: {'the': 3, 'cat': 1, 'dog': 1, 'bird': 1}
4

Check for a palindrome

Return True if a string is a palindrome, ignoring case and any non-alphanumeric characters.

Example:

Input:  "A man, a plan, a canal: Panama"
Output: True
5

Two Sum

Given a list of integers and a target, return the indices of the two numbers that add up to the target. Assume exactly one solution exists.

Example:

Input:  nums = [2, 7, 11, 15], target = 9
Output: [0, 1]   # because nums[0] + nums[1] == 9
6

Flatten a nested list

Given a list that may contain nested lists to any depth, return a single flat list of all the values in order.

Example:

Input:  [1, [2, [3, 4], 5], [6]]
Output: [1, 2, 3, 4, 5, 6]
7

Fibonacci sequence

Return a list of the first n Fibonacci numbers, starting from 0, 1. Aim for an efficient iterative solution.

Example:

Input:  n = 8
Output: [0, 1, 1, 2, 3, 5, 8, 13]
8

A simple class: BankAccount

Write a BankAccount class with an initial balance, a deposit method, and a withdraw method that raises ValueError on insufficient funds. Expose the current balance.

Example:

acct = BankAccount(100)
acct.deposit(50)
acct.withdraw(30)
print(acct.balance)   # 120
acct.withdraw(1000)   # raises ValueError

Answer Key & Solutions

Section A answers with explanations, followed by full solutions for Section B

Section A — Answers

  • A1: (b) [1, 2, 3, 4]. b = a binds another name to the same list object, so appending through b mutates the object a also refers to.
  • A2: (b) "yth". Slicing s[1:4] includes index 1 up to but not including index 4 — characters at positions 1, 2, 3.
  • A3: (b) "nohtyp". A step of -1 walks the string backwards, reversing it.
  • A4: (b) [1] then [1, 2]. The default list is created once when the function is defined and shared across calls, so it accumulates values.
  • A5: (a) False True False True. Empty containers and 0 are falsy; a non-empty list and a non-empty string (even "0") are truthy.
  • A6: (a) 3 3.5 1. // is floor division, / is true (float) division, and % is the remainder.
  • A7: (b) 0. dict.get returns the supplied default when the key is missing instead of raising KeyError.
  • A8: (b) 3. A set keeps only distinct values, so the duplicates collapse to {1, 2, 3}.
  • A9: (a) {0: 0, 1: 1, 2: 4}. A dict comprehension maps each key to its square over range(3).
  • A10: (b) -1. int("abc") raises ValueError, which is caught and sets x = -1.

B1 — FizzBuzz

def fizzbuzz(n):
    for i in range(1, n + 1):
        if i % 15 == 0:
            print("FizzBuzz")
        elif i % 3 == 0:
            print("Fizz")
        elif i % 5 == 0:
            print("Buzz")
        else:
            print(i)

Check i % 15 (3 and 5 together) before the individual checks. Runs in O(n) time.

B2 — Reverse the words

def reverse_words(sentence):
    return " ".join(reversed(sentence.split()))

str.split() with no argument splits on any whitespace and drops empties; reversed reverses the word list and join rebuilds the string. O(n) in the length of the input.

B3 — Word frequency

def word_count(text):
    counts = {}
    for word in text.lower().split():
        counts[word] = counts.get(word, 0) + 1
    return counts

# Idiomatic alternative:
# from collections import Counter
# return dict(Counter(text.lower().split()))

dict.get(word, 0) avoids a separate "key exists" check. collections.Counter is the idiomatic standard-library tool. O(n) over the words.

B4 — Palindrome check

def is_palindrome(s):
    cleaned = [c.lower() for c in s if c.isalnum()]
    return cleaned == cleaned[::-1]

Keep only alphanumeric characters, lowercase them, then compare against the reverse. O(n) time and O(n) extra space.

B5 — Two Sum

def two_sum(nums, target):
    seen = {}                      # value -> index
    for i, n in enumerate(nums):
        complement = target - n
        if complement in seen:
            return [seen[complement], i]
        seen[n] = i
    return None

A hash map lets you look up the needed complement in O(1), giving an overall O(n) single-pass solution instead of the O(n²) brute force.

B6 — Flatten a nested list

def flatten(items):
    result = []
    for item in items:
        if isinstance(item, list):
            result.extend(flatten(item))
        else:
            result.append(item)
    return result

Recursion handles arbitrary nesting depth: lists are flattened in place via extend, scalars are appended. O(n) in the total number of elements.

B7 — Fibonacci sequence

def fibonacci(n):
    seq = []
    a, b = 0, 1
    for _ in range(n):
        seq.append(a)
        a, b = b, a + b
    return seq

Tuple assignment a, b = b, a + b advances both values without a temporary variable. Iterative and O(n), avoiding the exponential cost of naive recursion.

B8 — BankAccount class

class BankAccount:
    def __init__(self, balance=0):
        self.balance = balance

    def deposit(self, amount):
        if amount <= 0:
            raise ValueError("Deposit must be positive")
        self.balance += amount

    def withdraw(self, amount):
        if amount > self.balance:
            raise ValueError("Insufficient funds")
        self.balance -= amount

__init__ sets the initial state; withdraw validates funds before mutating and raises ValueError when the request exceeds the balance. Each operation is O(1).

Related Resources

Continue practicing and deepen your skills

SQL Practice Test

Self-check SQL challenges covering joins, aggregation, and query writing with full solutions.

Start Practicing

Machine Learning Practice Test

Test your understanding of core ML concepts, models, and evaluation with a complete answer key.

Start Practicing

Data Science Python Cheat Sheet

A quick reference for Python data-science workflows, NumPy, and pandas essentials.

View Cheat Sheet

Python for Data Analysis

A full course applying Python to real-world data analysis tasks, from basics to projects.

Explore Course

Frequently Asked Questions

Common questions about this Python practice test