🎓 Velnov

🐍 Python · Topic 20 of 20

Interview Questions — Python Questions with Answers

Start with the study notes on Interview Questions (definitions, examples and a quick revision), then work through 30 practice questions, each with the correct answer and a clear explanation of why it is right. When you are ready, take this topic as an interactive quiz to test yourself.

0 easy · 1 medium · 29 hard · Part of Python: Master Python from basics to advanced - 20 topics.

Topic overview

Python Interview Questions – the classic traps, explained

1. How to answer “what is the output?”

Interviewers love short snippets with a surprise. Read slowly and ask:

2. 1. Mutable default arguments

A default list is created once and shared by every call.

def f(a, b=[]):
    b.append(a)
    return b

print(f(1))
print(f(2))
Output[1]
[1, 2]

Remember: Fix: use b=None, then if b is None: b = [] inside the function.

3. 2. Shared lists and +=

b = a shares one list, and += on a list changes it in place.

a = b = [1, 2]
a += [3]
print(a, b)
x = [1, 2, 3]
y = x[:]             # a real copy
y.append(4)
print(x, y)
Output[1, 2, 3] [1, 2, 3]
[1, 2, 3] [1, 2, 3, 4]

4. 3. Numbers and precedence

print(0.1 + 0.2 == 0.3)
print(2 ** 3 ** 2)
print(3 * "ab" + "c")
print(-7 // 2, round(2.5))
OutputFalse
512
abababc
-4 2

Example: Floats are approximate; ** is right-associative; * binds before +; // rounds down; round() uses banker's rounding.

5. 4. bool is an int

print(True == 1, False == 0, True + True)
print([1] == [True])
print(sum([True, False, True]))
OutputTrue True 2
True
2

6. 5. Truthiness is not equality

An empty list is falsy, but it is not equal to False. Any non-empty string is truthy, even "False".

print([] == False, bool([]) == False)
print(bool("False"), bool("0"), bool(0), bool(""))
OutputFalse True
True True False False

7. 6. finally always wins

finally runs even after return, and a return inside finally replaces the earlier one.

def f():
    try:
        return 1
    finally:
        return 2

print(f())
Output2

8. 7. Immutability is shallow

A tuple's items can't be replaced, but a list inside a tuple can still change.

t = (1, 2, [3, 4])
t[2].append(5)
print(t)
Output(1, 2, [3, 4, 5])

9. 8. Loop variables and late binding

for i in range(3):
    pass
print(i)                       # the for-loop variable survives

funcs = [lambda: i for i in range(3)]
print([f() for f in funcs])    # all see the last i
Output2
[2, 2, 2]

10. 9. Strings and ranges

print("ab" in "banana", "ba" in "banana")
print("abc".find("d"), "abc".find("b"))
print(list(range(3, 0)), list(range(3, 0, -1)))
print("-".join(str(x) for x in range(3)))
OutputFalse True
-1 1
[] [3, 2, 1]
0-1-2

11. 10. Quick concept questions

12. Common misconceptions

MisconceptionCorrect understanding
f(2) after f(1) returns [2] when the default is [].The default list is shared, so it returns [1, 2].
[] == False is True.An empty list is falsy but not equal to False.
2 ** 3 ** 2 is 64.It is 2 ** 9 = 512.
A tuple can never change at all.Its items can't be replaced, but a list inside it can change.
After for i in range(3), i is undefined.The for-loop variable stays, holding 2.

13. Quick revision

Mutable default
Shared between calls; use None.
Aliasing
b = a shares one object.
Right-associative **
2 ** 3 ** 2 = 2 ** 9.
bool is int
True == 1, False == 0.
Truthy vs equal
bool([]) is False, but [] != False.
finally
Runs even after return; its return wins.
Shallow immutability
A tuple's inner list can change.
Late binding
Closures see a variable's latest value.

14. Test your understanding

  1. What does print(0.1 + 0.2 == 0.3) print?

    Show answer

    False

  2. What does print(2 ** 3 ** 2) print?

    Show answer

    512

  3. a = b = [1]; a += [2]. What is b?

    Show answer

    [1, 2]

  4. What is True + True?

    Show answer

    2

  5. What does [] == False give?

    Show answer

    False

  6. try: return 1, finally: return 2. What is returned?

    Show answer

    2

  7. What is i after for i in range(3): pass?

    Show answer

    2

  8. What is bool("False")?

    Show answer

    True (a non-empty string).

Key takeaway: Most Python “trick” questions come down to five ideas: shared mutable objects, operator precedence, bool being an int, truthiness vs equality, and late binding.

Notes written by Velnov. Every code example with an output was run in Python 3 to check that the output shown is exactly what Python prints.

Key concepts in this topic

Mutable defaultsCommon trapsFloating pointiscloseReferencesAliasingOperator precedenceAssociativitybool as intTruthinessTruthiness vs equalityComprehensionsList concatenationSlicingReverseList equalityin operatorSubstringstry/finallyreturnString operationsCopyingGotchasTuple immutability

Jump to: Medium · Hard

Medium questions (1)

Q8. medium

What is the output? s = "hello" print(s[::-1])

  1. A olleh
  2. B hello
  3. C hell
  4. D Error

Answer: A — olleh

A slice with step -1 walks the string backwards, reversing it: 'olleh'. The idiomatic Python reverse - also used to check palindromes with s == s[::-1].

SlicingReverse

Hard questions (29)

Q1. hard

What is the output? def f(a, b=[]): b.append(a) return b print(f(1)) print(f(2))

def f(a, b=None):
    if b is None:
        b = []
    b.append(a)
    return b
  1. A [1] then [1, 2] - the default list is created ONCE and reused across calls
  2. B [1] then [2]
  3. C [1, 2] then [1, 2]
  4. D Error

Answer: A — [1] then [1, 2] - the default list is created ONCE and reused across calls

The mutable default argument trap. The default [] is created once at definition and shared by every call that omits b, so it accumulates. Fix: use b=None and create the list inside.

Mutable defaultsCommon traps

Q2. hard

What is the output? print(0.1 + 0.2 == 0.3)

import math
print(math.isclose(0.1 + 0.2, 0.3))   # True
  1. A False - floating-point rounding makes 0.1 + 0.2 = 0.30000000000000004
  2. B True
  3. C Error
  4. D 0.3

Answer: A — False - floating-point rounding makes 0.1 + 0.2 = 0.30000000000000004

Floats are binary approximations; 0.1 and 0.2 can't be represented exactly. Never compare floats with ==; use math.isclose(a, b) or round to a few decimals.

Floating pointisclose

Q3. hard

What is the output? a = [1, 2, 3] b = a b.append(4) print(a)

  1. A [1, 2, 3, 4] - a and b are two names for the SAME list
  2. B [1, 2, 3]
  3. C [4]
  4. D Error

Answer: A — [1, 2, 3, 4] - a and b are two names for the SAME list

b = a does not copy; both names reference one list. Mutating through b is visible through a. For an independent copy: b = a.copy() or b = a[:].

ReferencesAliasing

Q4. hard

What is the output? print(2 ** 3 ** 2)

  1. A 512 - ** is right-associative, so it's 2 ** (3 ** 2) = 2 ** 9
  2. B 64 - (2 ** 3) ** 2
  3. C 12
  4. D 18

Answer: A — 512 - ** is right-associative, so it's 2 ** (3 ** 2) = 2 ** 9

Exponentiation groups right-to-left (unlike most operators). So 3 ** 2 = 9 first, then 2 ** 9 = 512. A favorite precedence gotcha.

Operator precedenceAssociativity

Q5. hard

What is the output? print(True == 1, False == 0, True + True)

  1. A True True 2 - bool is a subclass of int (True is 1, False is 0)
  2. B False False 0
  3. C True True True
  4. D Error

Answer: A — True True 2 - bool is a subclass of int (True is 1, False is 0)

Booleans ARE integers under the hood: True equals 1, False equals 0, and they do arithmetic. That's why sum([True, False, True]) counts the Trues (2).

bool as intTruthiness

Q6. hard

What is the output? print([] == False, bool([]) == False)

  1. A False True - an empty list is falsy but NOT equal to False
  2. B True True
  3. C False False
  4. D Error

Answer: A — False True - an empty list is falsy but NOT equal to False

[] == False compares a list to a boolean (different values) -> False. But bool([]) converts the empty list to False first -> True. Truthiness (used by if) is different from == equality.

Truthiness vs equality

Q7. hard

What is the output? print([i for i in range(3)] + [i*2 for i in range(3)])

  1. A [0, 1, 2, 0, 2, 4]
  2. B [0, 1, 2, 2, 4, 6]
  3. C [0, 2, 4]
  4. D Error

Answer: A — [0, 1, 2, 0, 2, 4]

First comprehension: [0, 1, 2]. Second: [0, 2, 4]. + concatenates the two lists -> [0, 1, 2, 0, 2, 4].

ComprehensionsList concatenation

Q9. hard

What is the output? print(1 == True, [1] == [True])

  1. A True True - 1 equals True, so the lists compare equal too
  2. B True False
  3. C False False
  4. D Error

Answer: A — True True - 1 equals True, so the lists compare equal too

1 == True is True (bool is int). List equality compares elements: 1 == True is True, so [1] == [True]. Consistent once you know True behaves as 1.

bool as intList equality

Q10. hard

What is the output? print("a" in "banana", "ba" in "banana", "ab" in "banana")

  1. A True True False - 'in' checks for a contiguous SUBSTRING
  2. B True True True
  3. C False False False
  4. D Error

Answer: A — True True False - 'in' checks for a contiguous SUBSTRING

in tests substrings: 'a' and 'ba' appear in 'banana', but 'ab' does not (the letters aren't adjacent in that order). Substring, not subsequence.

in operatorSubstrings

Q11. hard

What is the output? def f(): try: return 1 finally: return 2 print(f())

  1. A 2 - finally's return OVERRIDES the try's return
  2. B 1
  3. C 1 then 2
  4. D Error

Answer: A — 2 - finally's return OVERRIDES the try's return

finally always runs, and its return replaces the pending one from try. This is why returning inside finally is discouraged - it silently swallows the real result (and even exceptions).

try/finallyreturn

Q12. hard

What is the output? print(3 * "ab" + "c")

  1. A ababcabc
  2. B abababc
  3. C ababab c
  4. D Error

Answer: B — abababc

* binds tighter than +: 3 * "ab" = "ababab" first, then + "c" -> "abababc". Precedence applies to string operators too.

Operator precedenceString operations

Q13. hard

What is the output? x = [1, 2, 3] y = x[:] y.append(4) print(x, y)

  1. A [1, 2, 3] [1, 2, 3, 4] - x[:] made an independent copy
  2. B [1, 2, 3, 4] [1, 2, 3, 4]
  3. C [1, 2, 3] [4]
  4. D Error

Answer: A — [1, 2, 3] [1, 2, 3, 4] - x[:] made an independent copy

x[:] creates a shallow copy, so y is a separate list. Appending to y leaves x unchanged. (Contrast with y = x, which would share the list.)

SlicingCopying

Q14. hard

What is the output? print(bool("False"), bool("0"), bool(0), bool(""))

  1. A True True False False
  2. B False False False False
  3. C True True True True
  4. D False True False True

Answer: A — True True False False

Any NON-EMPTY string is truthy - even "False" and "0". Only the empty string is falsy. The number 0 is falsy. So: True, True, False, False.

TruthinessGotchas

Q15. hard

What is the output? a = (1, 2, [3, 4]) a[2].append(5) print(a)

  1. A (1, 2, [3, 4, 5]) - the tuple is immutable but its inner LIST is mutable
  2. B Error - tuples can't change
  3. C (1, 2, [3, 4])
  4. D (1, 2, 3, 4, 5)

Answer: A — (1, 2, [3, 4, 5]) - the tuple is immutable but its inner LIST is mutable

A tuple can't have its elements REPLACED, but if an element is itself mutable (a list), that object can still be modified. Immutability is shallow.

Tuple immutabilityMutable elements

Q16. hard

What is the output? print(len("café"))

  1. A 4 - Python 3 strings count CHARACTERS, not bytes
  2. B 5
  3. C 3
  4. D Error

Answer: A — 4 - Python 3 strings count CHARACTERS, not bytes

In Python 3, strings are sequences of Unicode characters, so 'café' has length 4 regardless of how many bytes it takes to encode. (Encoded as UTF-8 bytes it would be 5.)

Unicodelen()

Q17. hard

What is the output? print(list(range(0)), list(range(5, 5)), list(range(3, 0)))

  1. A [] [] [] - all three ranges are empty
  2. B [0] [5] [3, 2, 1]
  3. C Error
  4. D [] [] [3, 2, 1]

Answer: A — [] [] [] - all three ranges are empty

range(0) and range(5,5) produce nothing. range(3, 0) is also empty because it counts UP by default and 3 is already past 0 - you'd need range(3, 0, -1) to count down.

range()Empty ranges

Q18. hard

What is the output? print("5" + "5", "5" * 2, int("5") + 5)

  1. A 55 55 10
  2. B 10 10 10
  3. C 55 25 10
  4. D Error

Answer: A — 55 55 10

"5" + "5" joins strings -> "55". "5" * 2 repeats -> "55". int("5") + 5 does math -> 10. Same-looking data behaving three ways depending on type.

Type behaviorOperators

Q19. hard

What is the output? x = {1, 2, 3} y = {3, 4, 5} print(x & y, x | y, x ^ y)

  1. A {3} {1,2,3,4,5} {1,2,4,5}
  2. B {3} {3} {3}
  3. C {1,2} {4,5} {3}
  4. D Error

Answer: A — {3} {1,2,3,4,5} {1,2,4,5}

& intersection (common: {3}), | union (all: {1,2,3,4,5}), ^ symmetric difference (in one but not both: {1,2,4,5}).

Set operations

Q20. hard

What is the output? nums = [1, 2, 3, 4] print(nums[::2], nums[1::2], nums[::-2])

  1. A [1, 3] [2, 4] [4, 2]
  2. B [1, 2] [3, 4] [4, 3]
  3. C [2, 4] [1, 3] [1, 3]
  4. D Error

Answer: A — [1, 3] [2, 4] [4, 2]

[::2] every other from start -> [1,3]. [1::2] every other from index 1 -> [2,4]. [::-2] every other going backwards -> [4,2].

SlicingStep

Q21. hard

What is the output? print(sorted([3, 1, 2]) is sorted([3, 1, 2]))

  1. A False - sorted() returns a NEW list each call, so they're different objects
  2. B True
  3. C Error
  4. D [1, 2, 3]

Answer: A — False - sorted() returns a NEW list each call, so they're different objects

Both calls produce equal lists ([1,2,3]), but they're separate objects in memory, so 'is' (identity) is False. == would be True. Classic is-vs-== distinction.

is vs ==sorted()

Q22. hard

What is the output? d = {"a": 1, "b": 2} print([k for k in d], [v for v in d.values()])

  1. A ['a', 'b'] [1, 2]
  2. B [1, 2] ['a', 'b']
  3. C ['a', 'b'] ['a', 'b']
  4. D Error

Answer: A — ['a', 'b'] [1, 2]

Iterating a dict directly gives its KEYS (['a', 'b']); .values() gives the values ([1, 2]). A frequent point of confusion when looping dicts.

Dict iterationkeys/values

Q23. hard

What is the output? print("abc".find("d"), "abc".find("b"))

  1. A -1 1 - find returns -1 when not found, else the index
  2. B None 1
  3. C Error 1
  4. D 0 1

Answer: A — -1 1 - find returns -1 when not found, else the index

find returns the index of the substring, or -1 if absent. 'd' isn't there (-1); 'b' is at index 1. (index() would raise ValueError instead of returning -1.)

find()index()

Q24. hard

What is the output? print(list(map(lambda x: x**2, filter(lambda x: x % 2, range(6)))))

  1. A [1, 9, 25] - keep odds (1,3,5), then square them
  2. B [0, 4, 16]
  3. C [1, 4, 9, 16, 25]
  4. D [0, 1, 4, 9, 16, 25]

Answer: A — [1, 9, 25] - keep odds (1,3,5), then square them

filter keeps values where x % 2 is truthy (odd): 1, 3, 5. map squares them: 1, 9, 25. Read inside-out. A comprehension would be [x**2 for x in range(6) if x % 2].

map()filter()lambda

Q25. hard

What is the output? a = b = [1, 2] a += [3] print(a, b)

  1. A [1, 2, 3] [1, 2, 3] - += mutates the shared list in place
  2. B [1, 2, 3] [1, 2]
  3. C [1, 2] [1, 2, 3]
  4. D Error

Answer: A — [1, 2, 3] [1, 2, 3] - += mutates the shared list in place

a and b point to the same list. For lists, += calls extend (in-place mutation), so both names see [1, 2, 3]. (For an int, += would rebind and NOT affect the other name.)

AliasingIn-place operators

Q26. hard

What is the output? print("-".join([str(x) for x in range(3)]))

  1. A 0-1-2
  2. B 012
  3. C 0 1 2
  4. D ['0-1-2']

Answer: A — 0-1-2

The comprehension makes ['0', '1', '2'] (join needs strings, not ints), then join glues them with '-' -> '0-1-2'.

join()Comprehensions

Q27. hard

What is the output? x = 1 print(x, end="") print(x + 1)

  1. A 12 (on one line) - end="" removes the newline after the first print
  2. B 1 then 2 on separate lines
  3. C 1 2
  4. D 3

Answer: A — 12 (on one line) - end="" removes the newline after the first print

end="" replaces the default trailing newline with nothing, so the second print continues on the same line: '1' then '2' -> '12'.

print endOutput formatting

Q28. hard

What is the output? print(max("apple", "banana", key=len), max("apple", "banana"))

  1. A banana banana - one by LENGTH, the other alphabetically (b > a)
  2. B apple apple
  3. C banana apple
  4. D apple banana

Answer: A — banana banana - one by LENGTH, the other alphabetically (b > a)

With key=len, max compares lengths: 'banana' (6) wins. Without key, max compares alphabetically: 'banana' > 'apple' because 'b' > 'a'. Both give 'banana' here, for different reasons.

max()key functions

Q29. hard

What is the output? print(type([]) == list, type([]) is list, isinstance([], list))

  1. A True True True - all three confirm [] is a list
  2. B True False True
  3. C False False True
  4. D Error

Answer: A — True True True - all three confirm [] is a list

type([]) is the list class. == compares it to list (True); is checks identity - and classes are singletons, so True; isinstance is the preferred check (True). All three agree here, but isinstance is best because it respects subclasses.

type()isinstance()

Q30. hard

The famous one - what is the output? for i in range(3): pass print(i)

  1. A 2 - the loop variable survives with its LAST value after the loop
  2. B 3
  3. C NameError
  4. D 0

Answer: A — 2 - the loop variable survives with its LAST value after the loop

Unlike comprehensions, a for-loop variable leaks into the surrounding scope and keeps its final value (2, the last item of range(3)). If range were empty, i would never be defined.

Loop variable scopeGotchas

Practice “Interview Questions” as a quiz