These are not trick questions. They are Python behaving exactly as designed. But if you do not know these behaviors, they will trip you up in interviews and in production code.
I have collected the seven that appear most often in technical screens. Each one has a reason. Learn the reason and you will never get caught off guard.
1. The List That Remembers Everything
def add_item(item, lst=[]):
lst.append(item)
return lst
print(add_item("a"))
print(add_item("b"))
print(add_item("c"))
Most people guess:
['a']
['b']
['c']
Actual output:
['a']
['a', 'b']
['a', 'b', 'c']
Why: Default argument values are evaluated once when the function is defined, not each time it is called. The list [] lives inside the function object and persists across calls.
2. The Copy That Is Not a Copy
a = [1, 2, 3]
b = a
b.append(4)
print(a)
Most people guess: [1, 2, 3]
Actual output: [1, 2, 3, 4]
Why: b = a does not copy the list. Both names reference the same object in memory. Mutating through one name affects the other.
3. The Integer That Is Not Equal to Itself
x = 1000
y = 1000
print(x == y)
print(x is y)
Output:
True
False
Why: Python caches small integers (typically -5 to 256) as singletons. For numbers outside that range, two equal integers can be different objects. The == operator checks value equality, while is checks object identity.
4. The Loop Variable That Escapes
for i in range(5):
pass
print(i)
Most people expect: An error.
Actual output: 4
Why: Python loop variables are not scoped to the loop block. They persist in the enclosing scope after the loop ends. The variable i holds the last value it was assigned, which is 4.
5. The String Multiplication Trap
result = [[]] * 3
result[0].append(1)
print(result)
Most people guess: [[1], [], []]
Actual output: [[1], [1], [1]]
Why: The * operator on a list containing a mutable object creates multiple references to the exact same inner object, not distinct copies. All three entries point to the same inner list.
6. The Generator That Runs Out
gen = (x for x in range(3))
print(list(gen))
print(list(gen))
Output:
[0, 1, 2]
[]
Why: Generators are lazy and stateful. Once exhausted they do not restart. The second list(gen) call finds no values remaining and returns an empty list.
7. The Chained Comparison Fallacy
print(1 < 2 < 3)
print(3 > 2 > 5)
Output:
True
False
Why: Python supports chained comparisons as a series of pairwise checks. 3 > 2 > 5 evaluates as 3 > 2 and 2 > 5 which simplifies to True and False, resulting in False. This is actually the mathematically correct behavior, but many developers coming from other languages expect strictly left-to-right evaluation only.
Practice All of These
If you want to practice predicting Python output with immediate feedback, PyCodeIt generates problems covering all of these concepts and hundreds more. It is completely free, requires no account, and serves up a unique problem every session.
Bookmark this post and test yourself on each one without scrolling to the answer first. That is how pattern recognition builds. Try it at pycodeit.com.
Written by the developer behind PyCodeIt, a free AI-powered Python dry-run practice platform for technical interview preparation.
Top comments (0)