How to Use This Guide
Reading interview answers builds recognition, not recall. The way to convert this page into an offer is to treat every snippet as an experiment: predict the output, run it in CoderFile's Python editor, then change one line and predict again. Ten minutes of that beats an hour of scrolling.
The questions below are grouped the way interviews actually flow — warm-up language questions first, then data structures, then a live coding challenge, then complexity follow-ups.
Language Fundamentals Interviewers Love
1. Why does this function remember its previous calls?
def add_item(item, basket=[]): basket.append(item) return basket print(add_item("apple"))
print(add_item("pear"))The default argument is evaluated once, when the function is defined, so every call without an explicit basket shares the same list. The output is ['apple'] then ['apple', 'pear']. The fix is the sentinel pattern: default to None and create the list inside the body.
2. What do these closures print?
funcs = [lambda: i for i in range(3)]
print([f() for f in funcs])It prints [2, 2, 2]. Python closures capture the variable, not its value at creation time. Bind eagerly with a default argument — lambda i=i: i — to get [0, 1, 2].
3. Shallow versus deep copy
import copy grid = [[0] * 3] * 3
grid[0][0] = 9
print(grid) # every row changed safe = copy.deepcopy([[0] * 3 for _ in range(3)])
safe[0][0] = 9
print(safe)Multiplying a list of lists repeats the same reference three times. This one appears constantly in grid and matrix problems, and getting it wrong silently corrupts an otherwise correct algorithm.
4. is versus ==
== compares value, is compares identity. Small integers and short strings are interned, so a is b can be true by accident for 256 and false for 257. Only use is for None, True, and False.
Data Structures and Complexity
Expect to justify a container choice out loud. Memorise this table:
- list — index O(1), append amortised O(1), insert/remove at front O(n), membership O(n).
- dict / set — insert, lookup, delete average O(1), worst case O(n) under pathological hashing.
- collections.deque — append and pop at both ends O(1); the right answer for queues and sliding windows.
- heapq — push and pop O(log n); the right answer for "top k" and streaming-median questions.
from collections import Counter, defaultdict, deque
import heapq words = "the quick brown fox jumps over the lazy dog the end".split()
print(Counter(words).most_common(3)) groups = defaultdict(list)
for w in words: groups[len(w)].append(w)
print(dict(groups)) print(heapq.nlargest(3, [5, 1, 9, 3, 7])) window = deque(maxlen=3)
for n in range(6): window.append(n)
print(list(window))Knowing Counter, defaultdict, deque, and heapq turns several "hard" questions into five-line answers, and interviewers read that as fluency with the standard library.
Generators, Iterators, and Memory
def fib(): a, b = 0, 1 while True: yield a a, b = b, a + b gen = fib()
print([next(gen) for _ in range(10)]) # Memory: a generator holds one value at a time
squares_list = [x * x for x in range(1_000_000)] # ~40MB
squares_gen = (x * x for x in range(1_000_000)) # a few hundred bytes
print(sum(squares_gen))The follow-up is always the same: "when would you use a generator over a list?" The answer is when the sequence is large, infinite, or streamed, and when you only need one pass. Mention that generators are single-use — iterating twice yields nothing the second time.
Classic Coding Challenges
Two Sum in one pass
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 [] print(two_sum([2, 7, 11, 15], 9))O(n) time, O(n) space. The brute-force nested loop is O(n²); saying that out loud before you optimise scores points.
Longest substring without repeats (sliding window)
def longest_unique(s): last, start, best = {}, 0, 0 for i, ch in enumerate(s): if ch in last and last[ch] >= start: start = last[ch] + 1 last[ch] = i best = max(best, i - start + 1) return best print(longest_unique("abcabcbb"))Group anagrams
from collections import defaultdict def group_anagrams(words): buckets = defaultdict(list) for w in words: buckets[tuple(sorted(w))].append(w) return list(buckets.values()) print(group_anagrams(["eat", "tea", "tan", "ate", "nat", "bat"]))Sorting each word is O(k log k); a 26-length character count is O(k) and is the optimisation interviewers fish for.
Binary search without off-by-one bugs
def bsearch(arr, target): lo, hi = 0, len(arr) - 1 while lo <= hi: mid = (lo + hi) // 2 if arr[mid] == target: return mid if arr[mid] < target: lo = mid + 1 else: hi = mid - 1 return -1 print(bsearch([1, 3, 5, 7, 9, 11], 9))Write it once from memory, then test the empty list, single element, first element, and last element. Those four cases catch nearly every off-by-one error.
Object-Oriented and Idiomatic Python
class Money: __slots__ = ("amount", "currency") def __init__(self, amount, currency="USD"): self.amount, self.currency = amount, currency def __repr__(self): return f"Money({self.amount}, {self.currency!r})" def __eq__(self, other): return (self.amount, self.currency) == (other.amount, other.currency) def __add__(self, other): if self.currency!= other.currency: raise ValueError("currency mismatch") return Money(self.amount + other.amount, self.currency) print(Money(5) + Money(7))Dunder methods, __slots__ for memory, context managers with __enter__/__exit__, and the difference between @staticmethod and @classmethod are the standard object-oriented round.
Interview Strategy That Actually Moves the Score
- Restate the problem and confirm input ranges, duplicates, and whether the input is sorted.
- Name a brute-force solution first with its complexity, then improve it. This proves you can reason, not just recall.
- Talk while you type. Silence reads as being stuck even when you are not.
- Test out loud on an empty input, a single element, and a duplicate-heavy input before saying you are done.
- Ask for the follow-up. "Would you like me to handle streaming input?" signals seniority.
Practise in a Real Runnable Editor
Because most companies now interview in a shared browser editor, the closest possible rehearsal is doing exactly that. Paste each challenge above into the Python editor, solve it without autocomplete, and run it. When you want structured repetition, the practice challenges grade your solution against hidden test cases, and the interview platform adds a second cursor and video so a friend can mock-interview you end to end.
Work through five questions a day for two weeks, redo the failures, and you will walk into the real screen having already had the experience — which is the entire point.