Python Interview Prep — Common Questions and Patterns
The Python questions that come up in real technical interviews, answered at senior-engineer depth.
Quick answer
Python interviews mix coding problems, which usually come down to a few patterns (hash maps, two pointers, sliding windows), with concept questions about mutability, copying, is versus ==, generators, decorators and the GIL. Explaining your reasoning matters as much as the final answer.
- A dict or set turns many O(n²) searches into O(n).
- Know the classic gotchas: mutable defaults, shallow copies, is vs ==.
- Clarify the requirements and test edge cases out loud.
def two_sum(nums, target):
seen = {}
for i, n in enumerate(nums):
if target - n in seen:
return seen[target - n], i
seen[n] = i
return None
print(two_sum([2, 7, 11, 15], 9))
print(two_sum([3, 2, 4], 6))
a = [1, 2]; b = [1, 2]
print(a == b, a is b)Output
(0, 1) (1, 2) True False
Everything From This Track, Interview-Ready
This lesson is different from the other 45 — instead of teaching one new topic in depth, it pulls together the gotchas, patterns, and trade-offs from across the entire curriculum into the format an actual technical interview uses: real questions, answered completely, organised by theme. If a question below references something unfamiliar, the module it was originally covered in is named — this is meant to be a review and synthesis, not a first introduction.
The Fundamentals Every Interview Assumes You Know Cold
Classes, Inheritance, and Encapsulation
Decorators, Generators, Closures, and Scope
What Separates Working Code From Production-Ready Code
Three Classic Problems, Worked Through Completely
Beyond conceptual questions, most technical interviews include at least one live coding problem. These three are among the most commonly seen — not because the exact problems repeat, but because the underlying patterns (hash-map lookups, in-place traversal, simple loop logic) generalise to a huge fraction of what actually gets asked.
1. Two Sum — the canonical hash-map pattern
Given a list of numbers and a target, return the indices of the two numbers that add up to the target. The naive approach checks every pair — O(n²). The optimal approach uses a dict to turn the "have I seen the complement before?" question into an O(1) lookup.
def two_sum(nums, target):
seen = {} # value -> index
for i, num in enumerate(nums):
complement = target - num
if complement in seen:
return [seen[complement], i]
seen[num] = i
return None # no valid pair found
two_sum([2, 7, 11, 15], 9) # [0, 1] — nums[0] + nums[1] == 2 + 7 == 9The key insight worth saying out loud in an interview: this is a single pass, building the dict as you go, checking each number's complement against numbers already seen before adding the current number — checking before inserting avoids matching a number with itself.
2. Reverse a String In Place — the two-pointer pattern
Given a mutable sequence, reverse it without allocating a second full copy. The two-pointer technique swaps from both ends toward the middle.
def reverse_in_place(chars):
left, right = 0, len(chars) - 1
while left < right:
chars[left], chars[right] = chars[right], chars[left]
left += 1
right -= 1
return chars
reverse_in_place(list("hello")) # ['o', 'l', 'l', 'e', 'h']Worth noting explicitly: this only works in place on a mutable sequence like a list — Python's actual str type is immutable, so "reversing a string in place" in real Python code is normally just text[::-1], and this exercise exists specifically to demonstrate the two-pointer technique on a mutable structure, a pattern that generalises far beyond strings (checking palindromes, partitioning arrays, and more).
3. FizzBuzz, With the Twist Interviewers Actually Care About
The most famous (and most maligned) interview question is rarely about the logic itself — it's a filter for whether a candidate can translate simple, precise rules into correct code under mild pressure, and increasingly, interviewers extend it with a follow-up to see how a candidate generalises a solution.
def fizzbuzz(n):
result = []
for i in range(1, n + 1):
if i % 15 == 0:
result.append("FizzBuzz")
elif i % 3 == 0:
result.append("Fizz")
elif i % 5 == 0:
result.append("Buzz")
else:
result.append(str(i))
return resultdef fizzbuzz_generalised(n, rules):
# rules: a list of (divisor, word) tuples, e.g. [(3, "Fizz"), (5, "Buzz")]
result = []
for i in range(1, n + 1):
word = "".join(w for d, w in rules if i % d == 0)
result.append(word or str(i))
return result
fizzbuzz_generalised(20, [(3, "Fizz"), (5, "Buzz"), (7, "Bazz")])The generalised version demonstrates something the basic version cannot: recognising that the original problem's hardcoded 3/5/15 logic is really a special case of "check divisibility against an arbitrary list of rules, in order" — exactly the kind of abstraction interviewers are listening for, without over-engineering a problem that did not ask for it.
4. Valid Parentheses — the stack pattern
Given a string of brackets, determine whether every opening bracket has a matching closing bracket in the correct order. This is the canonical example of the stack pattern — appearing constantly in problems involving nested or matched structures (parsing, balanced expressions, undo/redo history).
def is_valid(s):
pairs = {")": "(", "]": "[", "}": "{"}
stack = []
for char in s:
if char in pairs.values(): # an opening bracket — push it
stack.append(char)
elif char in pairs: # a closing bracket — must match the top of the stack
if not stack or stack.pop() != pairs[char]:
return False
return not stack # True only if every opening bracket was eventually matched and closed
is_valid("({[]})") # True
is_valid("({[})") # False — the "[" is closed by "}" out of order
is_valid("(") # False — nothing left to match it, stack is non-empty at the endA Python list, used with only .append() and .pop() (both O(1) at the end of a list), is the idiomatic way to implement a stack — there is no need for a dedicated stack class. The pattern to recognise going forward: any problem involving "does this nested/matched structure resolve correctly" is very often a stack in disguise.
An Interview Loop at a Series B Startup in Austin
A candidate is given a variant of the Two Sum problem, but the interviewer is far more interested in what happens after the first working solution than the solution itself. The candidate writes the O(n²) brute-force version first, gets it correct, and then the interviewer asks: "can you do better than O(n²)?"
The candidate talks through the trade-off out loud — a hash map trades additional space (O(n) extra memory for the dict) for reduced time complexity (O(n) instead of O(n²)) — then implements the optimised version cleanly, explaining the "check the complement before inserting the current number" detail without being prompted. They then proactively mention a genuine edge case: what should happen if no valid pair exists at all, and confirm with the interviewer what the function should return in that case before finalizing the code.
What the interviewer was actually evaluating
The hiring debrief afterward focused almost entirely on the trade-off discussion and the unprompted edge-case question — not on whether the candidate "knew" Two Sum, which is widely practiced and not itself a meaningful signal. The panel's own words: "anyone can memorise this exact problem. What we cannot fake is watching someone reason about a trade-off out loud and catch an edge case before we have to point it out." This is precisely why every Q&A section throughout this entire curriculum has consistently emphasised the why behind an answer, not just the correct final answer alone.
Four Misconceptions About How Interviews Are Actually Graded
🎯 Key Takeaways
- ✓Interviews reward reasoning out loud — trade-offs, edge cases, and iteration toward a better solution — at least as much as a single correct final answer.
- ✓A small set of recurring patterns (hash-map lookups for O(1) membership/complement checks, two pointers for in-place traversal, careful loop/condition logic) covers a large fraction of real coding interview questions.
- ✓The conceptual gotchas that come up constantly — mutable defaults, shallow vs deep copy, is vs ==, the GIL, __eq__/__hash__ consistency — are exactly the ones this curriculum flagged individually across earlier lessons, because they are also genuinely common real production bugs, not just interview trivia.
- ✓Clarifying ambiguous requirements before coding, and testing your own solution against edge cases unprompted, are consistently rated positively — they mirror real engineering practice, not just interview performance.
- ✓Type hints, testing, and clean code practices (covered in the Production & Career Readiness phase) come up constantly in interviews for any role beyond the most junior level — interviewers care whether you write production-quality code, not just code that solves the immediate problem.
🎉 Track Complete — All 46 Modules
You've completed the full Python track — foundations to advanced.
From your first print() statement through control flow, data structures, object-oriented design, functional patterns, concurrency, typing, testing, and now interview readiness — that is the complete arc of what a working professional Python engineer actually needs. Revisit any module as a reference whenever a real project calls for it; that is exactly what this track is for, not just a one-time read-through.
Quick check
a = [1, 2]; b = [1, 2]. What do a == b and a is b give?
HELP US IMPROVE
How was this lesson?
Your note is shared with the Chaduvuko team for review. Please don’t include personal or sensitive information.
Spotted a mistake or something unclear? Suggest a fix on GitHub or email us. Select the text first and it is quoted for you.
Discussion
0Have a better approach? Found something outdated? Share it — your knowledge helps everyone learning here.
