All interview guides

Python Interview Questions and Answers

24 questions that come up in Python technical interviews, each with the answer and an explanation of why it is right.

Topics covered: functions, comprehensions, numbers, closures, references, sequences, types, dicts, control flow, strings, generators, iteration, io, data model, classes.

Test yourself — 90 question bank

1. What does this print?

Advanced
python
def add(item, items=[]):
    items.append(item)
    return items

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

Answer: [1] then [1, 2]

Default arguments are evaluated once, when the function is defined — not on each call. The same list object is reused and accumulates across calls. Use `items=None` and create the list inside the function. This is the single most asked Python gotcha.

Official documentation →

2. What does this print?

Intermediate
python
nums = [1, 2, 3, 4]
print([n * 2 for n in nums if n % 2 == 0])

Answer: [4, 8]

The `if` filters first, keeping 2 and 4, then the expression doubles them. Reading order is: for, then if, then the expression at the front. A conditional *expression* would go before the `for` instead: `[n*2 if n%2==0 else n for n in nums]`.

Official documentation →

3. What does this print?

Beginner
python
x = 10
y = 3
print(x / y, x // y, x % y)

Answer: 3.3333333333333335 3 1

`/` always produces a float in Python 3, even when the division is exact. `//` is floor division and `%` gives the remainder. In Python 2 `/` truncated for integers, which is a classic source of migration bugs.

Official documentation →

4. What does this print?

Advanced
python
fns = [lambda: i for i in range(3)]
print([f() for f in fns])

Answer: [2, 2, 2]

The lambdas close over the variable `i`, not its value at creation time, and by the time they are called the loop has finished with `i == 2`. Bind it eagerly with a default argument: `lambda i=i: i`. The same trap exists in JavaScript with `var`.

Official documentation →

5. What does this print?

Intermediate
python
a = [1, 2]
b = a
b.append(3)
print(a, len(a))

Answer: [1, 2, 3] 3

`b = a` binds a second name to the same list object — it does not copy. Mutating through either name is visible from both. Use `a[:]`, `list(a)` or `copy.copy(a)` for an independent shallow copy.

Official documentation →

6. What does this print?

Beginner
python
items = ['a', 'b', 'c']
print(items[0], items[-1], items[1:3])

Answer: a c ['b', 'c']

Indexing starts at 0, and negative indices count from the end so `-1` is the last item. Slices are end-exclusive: `[1:3]` takes indices 1 and 2. Slicing never raises IndexError — out-of-range bounds are simply clamped.

Official documentation →

7. This raises TypeError. Which line is wrong?

Beginner
python
1  age = input('Age: ')
2  if age > 18:
3      print('adult')

Answer: Line 2 — input returns a string, which cannot be compared to an int

`input()` always returns a string, and Python refuses to compare str with int rather than guessing. Convert first: `age = int(input('Age: '))`. Wrap that in try/except ValueError if the user might type something non-numeric.

Official documentation →

8. This should collect the squares of even numbers but raises a TypeError. Which line is wrong?

Intermediate
python
1  result = []
2  for n in range(10):
3      if n % 2 == 0:
4          result = result.append(n ** 2)
5  print(result)

Answer: Line 4 — append returns None, so result becomes None after the first pass

Methods that mutate in place — `append`, `sort`, `extend`, `update` — return None by convention, precisely so you cannot chain them and mistake them for copies. Just call `result.append(...)` without assigning.

Official documentation →

9. What does this print?

Advanced
python
a = [1, 2, 3]
b = a
c = a[:]
a.append(4)
print(len(b), len(c))

Answer: 4 3

`b = a` binds another name to the same list, so it sees the append. `a[:]` creates a shallow copy, which does not. Note the copy is shallow: nested objects are still shared, which is what `copy.deepcopy` is for.

Official documentation →

10. What does this print?

Intermediate
python
d = {'a': 1, 'b': 2}
print(d.get('c'), d.get('c', 0))
try:
    print(d['c'])
except KeyError:
    print('missing')

Answer: None 0 then 'missing'

`get` returns None for a missing key, or a supplied default. Square-bracket access raises KeyError instead. Use `get` when absence is expected, and bracket access when a missing key is genuinely a bug you want to hear about.

Official documentation →

11. What does this print?

Beginner
python
d = {'name': 'Sam', 'age': 30}
print(d['name'], len(d), 'email' in d)

Answer: Sam 2 False

`len` on a dict counts key/value pairs, and `in` tests membership among the keys — not the values. To check values use `'Sam' in d.values()`.

Official documentation →

12. This is meant to modify the caller's list and also rebind it. The rebinding has no effect outside. Which line explains why?

Advanced
python
1  def process(items):
2      items.append(4)
3      items = [9, 9]
4      return None
5
6  data = [1, 2, 3]
7  process(data)

Answer: Line 3 — assignment rebinds the local name; it does not affect the caller

Python passes object references by value. Mutating the object (line 2) is visible to the caller; rebinding the name (line 3) only changes what the local variable points at. `data` ends up as [1, 2, 3, 4]. Return the new list if you want to replace it.

Official documentation →

13. What does this print?

Beginner
python
for i in range(3):
    print(i, end=' ')

Answer: 0 1 2

`range(3)` yields 0, 1, 2 — the stop value is exclusive. `range(1, 4)` would give 1, 2, 3. The `end=' '` argument replaces the default newline, keeping the output on one line.

Official documentation →

14. What does this print?

Intermediate
python
s = 'hello world'
print(s.split()[1], s[::-1][:5], s.replace('l', 'L', 2))

Answer: world dlrow heLLo world

`split()` on whitespace gives ['hello', 'world']. `[::-1]` reverses the whole string and `[:5]` takes 'dlrow'. `replace` with a count of 2 changes only the first two 'l' characters, leaving the one in 'world' alone.

Official documentation →

15. What does this print?

Advanced
python
def gen():
    yield 1
    yield 2

g = gen()
print(list(g), list(g))

Answer: [1, 2] []

A generator is a one-shot iterator: once exhausted it stays exhausted. The second `list()` gets nothing. This is why passing a generator to two consumers silently gives the second one an empty sequence — materialise it into a list first if it must be reused.

Official documentation →

16. Fill in the blank so the loop iterates over both index and value.

Beginner
python
for i, name in ____(['a', 'b']):
    print(i, name)

Answer: enumerate

`enumerate` yields (index, value) pairs, which is cleaner than `for i in range(len(items))` and then indexing. Pass `start=1` if you want human-friendly numbering.

Official documentation →

17. Fill in the blank so the file is closed automatically, even if an exception is raised.

Intermediate
python
____ open('data.txt') as f:
    content = f.read()

Answer: with

`with` invokes the context-manager protocol, so `__exit__` closes the file whether the block finishes normally or raises. Relying on the garbage collector to close files is unreliable — file descriptors can leak long before it runs.

Official documentation →

18. What does this print?

Intermediate
python
print(sorted([3, 1, 2]), [3, 1, 2].sort())

Answer: [1, 2, 3] None

`sorted()` returns a new sorted list and works on any iterable. `list.sort()` sorts in place and returns None. The naming convention is consistent across Python: functions return new objects, in-place methods return None.

Official documentation →

19. What does this print?

Beginner
python
s = 'Python'
print(len(s), s.upper(), s[0], s[-2:])

Answer: 6 PYTHON P on

'Python' has 6 characters, `[0]` is the first, and `[-2:]` takes the last two. String methods always return new strings — `s` itself is never modified, because strings are immutable.

Official documentation →

20. What does this print?

Advanced
python
print(0.1 + 0.2 == 0.3)
from decimal import Decimal
print(Decimal('0.1') + Decimal('0.2') == Decimal('0.3'))

Answer: False then True

Floats are binary and cannot represent 0.1 exactly, so the sum lands slightly above 0.3. `Decimal` constructed from strings is exact base-10 arithmetic, which is why it is the right choice for money. Note `Decimal(0.1)` from a float would inherit the same error.

Official documentation →

21. Which of these safely handle a missing key when counting occurrences? Select all that apply.

Intermediate
python
counts = {}

Answer: counts[k] = counts.get(k, 0) + 1

`get` with a default, `defaultdict(int)` and `Counter` all handle the first occurrence. Plain `counts[k] += 1` reads the key before writing it, so it raises KeyError the first time. `Counter` is the clearest for straight tallying.

Official documentation →

22. Fill in the blank so the class supports the `with` statement.

Advanced
python
class Conn:
    def __enter__(self):
        return self
    def ____(self, exc_type, exc, tb):
        self.close()

Answer: __exit__

`__enter__` and `__exit__` form the context-manager protocol. `__exit__` receives any exception details and can suppress it by returning True. `contextlib.contextmanager` is the lighter alternative for simple cases. `__del__` is not a substitute — its timing is not guaranteed.

Official documentation →

23. What does this print?

Beginner
python
def greet(name, greeting='Hello'):
    return f'{greeting}, {name}!'

print(greet('Sam'), greet('Ali', 'Hi'))

Answer: Hello, Sam! Hi, Ali!

A default parameter is used when the caller omits that argument. f-strings interpolate the expressions inside `{}` directly. Note defaults must come after non-default parameters in the signature.

Official documentation →

24. What does this print?

Advanced
python
class A:
    x = []

a, b = A(), A()
a.x.append(1)
b.x.append(2)
print(a.x, b.x)

Answer: [1, 2] [1, 2]

`x` is a class attribute, so both instances share one list. Mutating through either is visible from both. Per-instance state belongs in `__init__` as `self.x = []`. Note that `a.x = [...]` would create an instance attribute that shadows the class one — assignment and mutation behave differently here.

Official documentation →

Ready to test yourself?

The full Python bank has 90 questions across 3 difficulty levels — timed, shuffled, and scored.

Take the Python quiz