Python Refresher for Coding Interviews
A practical, no-fluff guide to the Python syntax, built-ins, and idioms you’ll reach for most during a technical interview.
If you’re building your full preparation plan, start with our How to Prepare for a Coding Interview guide. This syntax refresher also pairs perfectly with our Data Structures for Coding Interviews guide and its companion, the Python Data Structures Implementation Guide.
Want to test your Python fluency under real interview pressure? Try a mock coding interview on Intervu →
Why Python for Coding Interviews?
If you have the choice, Python is arguably the best language for technical interviews. Here is why:
- Concise Syntax: You have 45 minutes to solve a problem. Python’s lack of boilerplate (no semicolons, brackets, or strict typing) means you spend less time typing and more time thinking and communicating.
- Rich Standard Library: Built-in tools like
collections.Counter,defaultdict,heapq, andbisectallow you to implement complex logic in a single line. - No Integer Overflow: Python handles arbitrarily large integers automatically, eliminating a whole class of edge-case calculation bugs that plague C++ and Java candidates.
- Reads Like Pseudocode: Python’s English-like structure makes it incredibly easy for interviewers to follow your logic when you are explaining your approach out loud.
1. Data Types & Variables
# Integers (arbitrary precision — no overflow in Python!)
x = 10
big = 10 ** 18 # Works perfectly
# Float
pi = 3.14159
# Boolean
flag = True # Capitalized! True / False
# None
val = None
# Type checking
type(x) # <class 'int'>
isinstance(x, int) # True
# Multiple assignment
a, b, c = 1, 2, 3
a, b = b, a # Swap in one line
# Infinity
INF = float('inf')
NEG_INF = float('-inf')
Key tip: Python integers never overflow, which removes an entire class of bugs common in Java/C++.
2. Strings
s = "hello world"
# Basics
len(s) # 11
s[0] # 'h'
s[-1] # 'd'
s[1:5] # 'ello'
s[::-1] # 'dlrow olleh' (reverse)
# Methods
s.upper() # 'HELLO WORLD'
s.lower() # 'hello world'
s.strip() # removes leading/trailing whitespace
s.split() # ['hello', 'world']
s.split(',') # split by delimiter
','.join(['a','b','c']) # 'a,b,c'
s.replace('l', 'r') # 'herro worrd'
s.startswith('he') # True
s.endswith('ld') # True
s.find('world') # 6 (-1 if not found)
s.count('l') # 3
# Check character types
'abc'.isalpha() # True
'123'.isdigit() # True
'abc123'.isalnum() # True
# String → list of chars and back
chars = list(s)
''.join(chars) # back to string
# Ord / Chr — useful for encoding tricks
ord('a') # 97
chr(97) # 'a'
ord('z') - ord('a') # 25
# f-strings (preferred for formatting)
name, score = "Alice", 42
f"{name} scored {score} points" # 'Alice scored 42 points'
Key tip: Strings are immutable in Python. To build a string incrementally, collect characters in a list and ''.join() at the end — O(n) vs O(n²) for repeated +=.
3. Lists
lst = [3, 1, 4, 1, 5, 9]
# Access & slicing
lst[0] # 3
lst[-1] # 9
lst[1:4] # [1, 4, 1]
lst[::-1] # reversed copy
# Modify
lst.append(2) # add to end — O(1)
lst.insert(0, 99) # insert at index — O(n)
lst.pop() # remove & return last — O(1)
lst.pop(0) # remove & return first — O(n)
lst.remove(4) # remove first occurrence of value
del lst[2] # delete by index
# Info
len(lst) # length
lst.count(1) # count occurrences
lst.index(5) # first index of value
# Sort (in-place)
lst.sort() # ascending
lst.sort(reverse=True) # descending
# Sorted (returns new list)
sorted(lst)
sorted(lst, reverse=True)
sorted(lst, key=lambda x: -x)
# Initialize
zeros = [0] * 10 # [0, 0, 0, ..., 0]
matrix = [[0] * cols for _ in range(rows)] # 2D — use comprehension!
# Flatten
nested = [[1,2],[3,4]]
flat = [x for row in nested for x in row]
# Stack (use list as stack)
stack = []
stack.append(val) # push
stack.pop() # pop
# Queue (use deque, not list)
from collections import deque
q = deque()
q.append(val) # enqueue right
q.popleft() # dequeue left — O(1)
Key tip: Never use a plain list as a queue — list.pop(0) is O(n). Always use collections.deque.
4. Tuples & Sets
# Tuple — immutable, hashable (can be dict key or set element)
t = (1, 2, 3)
a, b, c = t # unpack
t[0] # 1
len(t) # 3
# Set — unordered, unique elements, O(1) average lookup
s = {1, 2, 3, 3} # {1, 2, 3}
s.add(4)
s.remove(2) # KeyError if missing
s.discard(99) # safe remove
2 in s # True — O(1)
# Set operations
a = {1, 2, 3}
b = {2, 3, 4}
a | b # union {1, 2, 3, 4}
a & b # intersection {2, 3}
a - b # difference {1}
a ^ b # symmetric diff {1, 4}
# Frozenset — immutable set (hashable)
fs = frozenset([1, 2, 3])
5. Dictionaries
d = {'a': 1, 'b': 2}
# Access
d['a'] # 1
d.get('z') # None (no KeyError)
d.get('z', 0) # 0 (default value)
# Modify
d['c'] = 3 # add/update
del d['a'] # delete key
d.pop('b') # remove and return value
d.pop('x', None) # safe pop with default
# Info
len(d) # number of keys
'a' in d # True — O(1)
d.keys() # dict_keys view
d.values() # dict_values view
d.items() # dict_items view — use in loops!
# Iterating
for k, v in d.items():
print(k, v)
# Merge (Python 3.9+)
merged = d1 | d2
# Default dict pattern (manual)
counts = {}
for char in "hello":
counts[char] = counts.get(char, 0) + 1
# setdefault
graph = {}
graph.setdefault('A', []).append('B')
6. Control Flow
# if / elif / else
if x > 0:
pass
elif x == 0:
pass
else:
pass
# Ternary
result = "pos" if x > 0 else "non-pos"
# for loop
for i in range(5): # 0, 1, 2, 3, 4
pass
for i in range(2, 10, 2): # 2, 4, 6, 8
pass
for i in range(9, -1, -1): # 9 down to 0
pass
# enumerate
for i, val in enumerate(lst):
pass
for i, val in enumerate(lst, start=1): # start index at 1
pass
# zip
for a, b in zip(list1, list2):
pass
# while
while condition:
pass
# break / continue / else on loops
for i in range(10):
if i == 5:
break
else:
# runs only if loop didn't break
pass
7. Functions
# Basic
def add(a, b):
return a + b
# Default args
def greet(name, greeting="Hello"):
return f"{greeting}, {name}!"
# *args and **kwargs
def f(*args, **kwargs):
print(args) # tuple
print(kwargs) # dict
# Lambda
square = lambda x: x * x
# Multiple return values (returns tuple)
def min_max(lst):
return min(lst), max(lst)
lo, hi = min_max([3, 1, 4])
# Nested functions / closures
def outer(x):
def inner(y):
return x + y
return inner
add5 = outer(5)
add5(3) # 8
8. List Comprehensions & Generators
# List comprehension
squares = [x**2 for x in range(10)]
evens = [x for x in range(20) if x % 2 == 0]
# Nested
matrix = [[i*j for j in range(3)] for i in range(3)]
# Dict comprehension
word_len = {w: len(w) for w in ["apple", "banana"]}
# Set comprehension
unique_lens = {len(w) for w in ["hi", "hey", "hello"]}
# Generator expression (memory-efficient)
total = sum(x**2 for x in range(1000000)) # no list created
# any / all with generators
any(x > 5 for x in lst) # True if at least one
all(x > 0 for x in lst) # True if all
9. Sorting
lst = [3, 1, 4, 1, 5]
# Built-ins
lst.sort() # in-place
sorted_lst = sorted(lst) # returns new list
# Custom key
words = ["banana", "fig", "apple", "kiwi"]
words.sort(key=len) # by length
words.sort(key=lambda w: w[-1]) # by last character
# Sort tuples by second element
pairs = [(1, 3), (2, 1), (3, 2)]
pairs.sort(key=lambda x: x[1])
# Sort by multiple criteria
data.sort(key=lambda x: (x[1], -x[0])) # by second asc, first desc
# Reverse
lst.sort(reverse=True)
sorted(lst, reverse=True)
# Max/Min with key
max(words, key=len) # longest word
min(pairs, key=lambda x: x[1])
10. Collections Module
from collections import Counter, defaultdict, deque, OrderedDict
# Counter — frequency map
c = Counter("abracadabra")
# Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
c.most_common(3) # [('a', 5), ('b', 2), ('r', 2)]
c['a'] # 5
c['z'] # 0 (no KeyError)
c1 = Counter("hello")
c2 = Counter("world")
c1 + c2 # combine counts
c1 - c2 # subtract counts
c1 & c2 # intersection (min of each)
c1 | c2 # union (max of each)
# defaultdict — never get a KeyError for missing keys
graph = defaultdict(list)
graph['A'].append('B') # no need to initialize
word_count = defaultdict(int)
for w in words:
word_count[w] += 1
nested = defaultdict(lambda: defaultdict(int))
# deque — efficient double-ended queue
dq = deque([1, 2, 3])
dq.append(4) # right end
dq.appendleft(0) # left end — O(1)
dq.pop() # right end
dq.popleft() # left end — O(1)
dq.rotate(1) # rotate right
deque(lst, maxlen=k) # sliding window of size k
11. Heapq Module
Python’s heapq is a min-heap by default.
import heapq
# Min-heap
heap = [3, 1, 4, 1, 5]
heapq.heapify(heap) # in-place, O(n)
heapq.heappush(heap, 2) # O(log n)
heapq.heappop(heap) # pops smallest, O(log n)
heap[0] # peek min without popping
heapq.nsmallest(3, lst) # 3 smallest elements
heapq.nlargest(3, lst) # 3 largest elements
# Max-heap trick: negate values
max_heap = []
heapq.heappush(max_heap, -val)
max_val = -heapq.heappop(max_heap)
# Heap of tuples (sorted by first element)
heapq.heappush(heap, (priority, item))
# Push then pop (more efficient)
heapq.heappushpop(heap, val) # push val, pop min
heapq.heapreplace(heap, val) # pop min, push val
12. Binary Search with bisect
import bisect
lst = [1, 3, 5, 7, 9] # must be sorted
# Find insertion point
bisect.bisect_left(lst, 5) # 2 (leftmost position to insert 5)
bisect.bisect_right(lst, 5) # 3 (rightmost position to insert 5)
bisect.bisect(lst, 5) # same as bisect_right
# Insert while keeping sorted
bisect.insort_left(lst, 6)
bisect.insort_right(lst, 6)
# Count occurrences in sorted list
def count_of(lst, val):
return bisect.bisect_right(lst, val) - bisect.bisect_left(lst, val)
# Find floor/ceiling
def floor(lst, val):
i = bisect.bisect_right(lst, val) - 1
return lst[i] if i >= 0 else None
def ceiling(lst, val):
i = bisect.bisect_left(lst, val)
return lst[i] if i < len(lst) else None
13. Itertools
import itertools
# Combinations & Permutations
list(itertools.combinations([1,2,3], 2))
# [(1,2), (1,3), (2,3)]
list(itertools.permutations([1,2,3], 2))
# [(1,2), (1,3), (2,1), (2,3), (3,1), (3,2)]
list(itertools.combinations_with_replacement([1,2,3], 2))
# [(1,1), (1,2), (1,3), (2,2), (2,3), (3,3)]
# Product (cartesian product)
list(itertools.product([0,1], repeat=3))
# all 3-bit binary strings
# Chain — flatten iterables
list(itertools.chain([1,2], [3,4], [5]))
# [1, 2, 3, 4, 5]
# Accumulate — running totals
list(itertools.accumulate([1,2,3,4]))
# [1, 3, 6, 10]
import operator
list(itertools.accumulate([1,2,3,4], operator.mul))
# [1, 2, 6, 24] (running product)
# groupby — group consecutive equal elements
data = sorted(people, key=lambda p: p['dept'])
for dept, members in itertools.groupby(data, key=lambda p: p['dept']):
print(dept, list(members))
14. Math & Numbers
import math
# Common constants
math.pi # 3.14159...
math.e # 2.71828...
math.inf # infinity
float('inf') # same
# Common functions
math.sqrt(16) # 4.0
math.floor(3.7) # 3
math.ceil(3.2) # 4
math.log(8, 2) # 3.0 (log base 2)
math.log2(8) # 3.0
math.log10(100) # 2.0
math.gcd(12, 8) # 4
math.lcm(4, 6) # 12 (Python 3.9+)
math.factorial(5) # 120
math.isqrt(17) # 4 (integer square root)
abs(-5) # 5
# Bit operations
x & y # AND
x | y # OR
x ^ y # XOR
~x # NOT
x << 1 # left shift (×2)
x >> 1 # right shift (÷2)
x.bit_length() # number of bits needed
bin(10) # '0b1010'
int('1010', 2) # 10 (binary string → int)
# Modular arithmetic
pow(base, exp, mod) # fast modular exponentiation
15. I/O & String Formatting
# Input (always returns string)
line = input()
n = int(input())
a, b = map(int, input().split())
lst = list(map(int, input().split()))
# Read multiple lines
import sys
data = sys.stdin.read().split()
# Print
print("hello", "world") # space-separated by default
print("hello", "world", sep=",") # 'hello,world'
print("hello", end="") # no newline
# f-strings
f"{value:.2f}" # 2 decimal places
f"{value:05d}" # zero-padded to width 5
f"{value:>10}" # right-align in width 10
f"{value:b}" # binary representation
f"{value:,}" # thousand separators
16. Common Patterns & Idioms
Two Pointers
def two_sum_sorted(arr, target):
l, r = 0, len(arr) - 1
while l < r:
s = arr[l] + arr[r]
if s == target:
return [l, r]
elif s < target:
l += 1
else:
r -= 1
Sliding Window
def max_sum_subarray(arr, k):
window = sum(arr[:k])
best = window
for i in range(k, len(arr)):
window += arr[i] - arr[i - k]
best = max(best, window)
return best
Fast & Slow Pointers (Floyd’s Cycle Detection)
def has_cycle(head):
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
return True
return False
BFS Template
from collections import deque
def bfs(graph, start):
visited = set([start])
queue = deque([start])
while queue:
node = queue.popleft()
for neighbor in graph[node]:
if neighbor not in visited:
visited.add(neighbor)
queue.append(neighbor)
DFS Template (Iterative)
def dfs(graph, start):
visited = set()
stack = [start]
while stack:
node = stack.pop()
if node not in visited:
visited.add(node)
stack.extend(graph[node])
DFS Template (Recursive)
def dfs(node, visited):
visited.add(node)
for neighbor in graph[node]:
if neighbor not in visited:
dfs(neighbor, visited)
Binary Search Template
def binary_search(arr, target):
lo, hi = 0, len(arr) - 1
while lo <= hi:
mid = lo + (hi - lo) // 2 # avoids overflow (good habit)
if arr[mid] == target:
return mid
elif arr[mid] < target:
lo = mid + 1
else:
hi = mid - 1
return -1 # or lo for insertion point
Dynamic Programming — Memoization
from functools import lru_cache
@lru_cache(maxsize=None)
def fib(n):
if n <= 1:
return n
return fib(n-1) + fib(n-2)
# Or use a dict manually
memo = {}
def dp(state):
if state in memo:
return memo[state]
# ... compute result
memo[state] = result
return result
Prefix Sum
def prefix_sum(arr):
prefix = [0] * (len(arr) + 1)
for i, val in enumerate(arr):
prefix[i+1] = prefix[i] + val
return prefix
# Range sum query: sum(arr[l:r+1]) = prefix[r+1] - prefix[l]
Unpacking & Enumerate Tricks
# Swap
a, b = b, a
# Unpack first and rest
first, *rest = [1, 2, 3, 4]
# Unpack last
*init, last = [1, 2, 3, 4]
# Iterate with index and value
for i, (x, y) in enumerate(pairs):
pass
# Zip with index
for i, (a, b) in enumerate(zip(list1, list2)):
pass
Quick Reference Cheat Sheet
| Task | Snippet |
|---|---|
| Reverse a list | lst[::-1] |
| Sort by custom key | sorted(lst, key=lambda x: ...) |
| Count characters | Counter(s) |
| Group adjacents | itertools.groupby(sorted_lst, key) |
| Flatten list | [x for row in matrix for x in row] |
| Default dict | defaultdict(list) / defaultdict(int) |
| Min/Max heap | heapq.heapify(lst) / negate for max |
| Binary search | bisect.bisect_left(lst, val) |
| Memoize recursive | @lru_cache(maxsize=None) |
| Infinity | float('inf') |
| Swap | a, b = b, a |
| Check all same | len(set(lst)) == 1 |
| Running sum | itertools.accumulate(lst) |
Good luck with your interviews! The best way to internalize these is to use them in actual problems — not just read through them. Pick a pattern, find 3 problems that use it, and code them up from scratch.