Python: Crazy Interview Questions
Imagine an interviewer hands you a slip of paper with this on it:
def foo(bar=[])
No context, just the question: what’s wrong with this code?
Strictly speaking, nothing. It’s valid Python (aside from the missing colon and function body), and a bug is only a bug when the code behaves differently from what the programmer intended.
Now let’s give the function a body:
def foo(bar=[]):
bar.append(1)
return bar
What would a typical Python programmer expect from calling foo() three times with no arguments?
foo() # [1]
foo() # [1]
foo() # [1]
That’s not what happens. The actual output is:
foo() # [1]
foo() # [1, 1]
foo() # [1, 1, 1]
Why? Python evaluates default argument values once, when the function is defined, not each time it’s called. The same list object is reused on every call. This differs from C/C++, and the behaviour resembles static variables there. That’s handy for caching or keeping state, but it’s rarely what you intended.
The usual fix:
def foo(bar=None):
if bar is None:
bar = []
bar.append(1)
return bar
The interviewer says: “Given a string S, replace the 3rd character with "A".”
You rightly note that the string might be empty or too short. “Ignore that,” they say. So you write:
def repl(S):
if len(S) >= 3:
S[2] = 'A' # index starts at 0
return S
The interviewer glances at it, ends the interview, and tells you HR will be in touch. (If an offer does come, you may want to think twice about working there.)
The problem: Python strings are immutable, so item assignment isn’t allowed. Instead, build a new string:
def repl(S):
if len(S) >= 3:
return S[:2] + 'A' + S[3:]
else:
return S
You’re shown this snippet:
F = [lambda x: i * x for i in range(5)]
If you haven’t fled the room yet, you’re already ahead of many. Here’s what the code is meant to do:
Fis a list of functions.- It holds 5 functions.
- Each takes one argument
xand should returnx * i, whereiis 0 for the first function, 1 for the second, and 4 for the last.
So you’d expect:
F[0](2) # 0
F[1](2) # 2
...
F[4](2) # 8
In reality:
F[0](2) # 8
F[1](2) # 8
...
F[4](2) # 8
Why? The lambdas look up i when they’re called, not when they’re created. By then the loop has finished and i is 4, so every function uses that value.
The usual fix is to bind the current value as a default argument:
F = [lambda x, i=i: i * x for i in range(5)]
Honestly, few experienced Python developers would get this right on the spot, and asking it in an interview will likely leave candidates with a poor impression of your company.
That’s all for today. Thanks for reading!