16. What does this nonlocal code print?
def outer():
x = 1
def inner():
nonlocal x
x = 2
inner()
print(x)
outer()
Output:
2
nonlocal x inside inner declares that x refers to the variable in the enclosing scope (outer), not a new local. So assigning x = 2 inside inner rebinds outer’s x, and outer prints 2. Without nonlocal, inner would create a local x and outer would still print 1.
17. What is printed by this global-scope code?
x = 1
def f():
x = 2
print("inside", x)
f()
print("outside", x)
Output:
inside 2
outside 1
The assignment x = 2 inside f creates a new local variable — it does not touch the global x. Function locals are determined at compile time, so the global is unaffected and prints 1. (Assigning to a global requires global x.)
18. What does this generator code print?
def gen():
yield 1
yield 2
yield 3
g = gen()
print(next(g))
print(list(g))
print(list(g))
Output:
1
[2, 3]
[]
Generators are exhaustible one-shot iterators. next(g) consumes 1. list(g) consumes the remaining 2 and 3, so the second list(g) is empty. This tests whether you remember that a generator has no __len__ and cannot be replayed.
19. What is printed by this exception-handling code?
try:
print("try")
raise ValueError("boom")
except ValueError as e:
print("caught", e)
finally:
print("finally")
Output:
try
caught boom
finally
The try block runs, the ValueError is caught by the matching except, and the finally block always runs — even on the success path, the error path, and the return/break path. Here the order is: try body, except handler, then finally.
20. What does this return + finally code print?
def f():
try:
return 1
finally:
print("finally")
print(f())
Output:
finally
1
The finally block executes before the return actually delivers its value. So "finally" prints first, then the function returns 1. finally cannot stop a return, but it always runs.
21. What is printed by this list-comprehension scoping code?
x = 100
result = [x for x in range(3)]
print(result)
print(x)
Output:
[0, 1, 2]
100
In Python 3, the loop variable of a list comprehension is scoped to the comprehension — it does not leak into the enclosing scope. x inside the comprehension shadows the global 100, and after the comprehension the global x is still 100. (Python 2 leaked; this changed in Python 3.)
22. What does this string immutability code print?
s = "hello"
t = s.upper()
print(s)
print(t)
Output:
hello
HELLO
Strings are immutable. s.upper() does not modify s — it returns a brand-new string, which is bound to t. s still holds "hello". The same logic applies to strip(), replace(), lower(), and slicing: they all return new strings.
23. What is printed by this chained comparison?
print(1 < 2 < 3)
print(3 > 2 > 3)
print(1 < 2 > 1)
Output:
True
False
True
Python supports chained comparisons — 1 < 2 < 3 is (1 < 2) and (2 < 3). The middle operand is evaluated only once. 3 > 2 > 3 is (3 > 2) and (2 > 3) = True and False = False. 1 < 2 > 1 is True and True = True.
24. What does this is check on interned strings print?
a = "hello world"
b = "hello world"
c = "hello " + "world"
d = "".join(["hello", " world"])
print(a is b)
print(a is c)
print(a is d)
Output:
True
True
False
a and b are identical literals, so they share one interned object. c is a compile-time concatenation of two literals, which the compiler folds into the same constant — so a is c is True. d is built at runtime by join, producing a new object, so a is d is False. Never rely on these — use == for strings.
25. What is printed by this sort vs sorted code?
a = [3, 1, 2]
b = a.sort()
c = sorted(a)
print(a)
print(b)
print(c)
Output:
[1, 2, 3]
None
[1, 2, 3]
a.sort() sorts in place and returns None. sorted(a) returns a new sorted list and leaves a alone. So after the two calls, a is sorted in place, b is None, and c is the new sorted copy. This is a frequent interview gotcha.
26. What does this while-with-else code print?
n = 3
while n > 0:
n -= 1
else:
print("done", n)
Output:
done 0
Like for, a while loop’s else runs when the loop terminates without break. Here the condition n > 0 becomes false naturally, so "done" prints and n is 0. If a break had fired, the else would be skipped.
27. What is printed by this default-evaluated-once code?
import time
def log(msg, when=time.time()):
print(msg, when)
t1 = time.time()
log("first")
time.sleep(0.01)
log("second")
Output:
first <same-timestamp>
second <same-timestamp>
Default argument values are evaluated once at function definition time. when=time.time() is evaluated when log is defined, and the same timestamp is reused for every call. This is why you never use a mutable or “fresh” value as a default — it is not re-evaluated per call.
28. What does this zip + dict code print?
keys = ["a", "b", "c"]
vals = [1, 2]
print(list(zip(keys, vals)))
print(dict(zip(keys, vals)))
Output:
[('a', 1), ('b', 2)]
{'a': 1, 'b': 2}
zip stops at the shortest iterable, so only two pairs are produced. dict() then turns those pairs into a dictionary. The leftover "c" is silently dropped.
29. What is printed by this object-identity code?
class Point:
pass
p1 = Point()
p2 = Point()
p3 = p1
print(p1 == p2)
print(p1 is p2)
print(p1 is p3)
Output:
False
False
True
Without a custom __eq__, == falls back to identity — the same as is. Two distinct Point() instances are neither == nor is equal. p3 is an alias for p1, so p1 is p3 is True.
30. What is printed by this exception-from-iteration code?
data = [1, 0, 3]
for x in data:
try:
print(10 // x)
except ZeroDivisionError:
print("skip")
print("end")
Output:
10
skip
3
end
10 // x raises ZeroDivisionError when x is 0, which the except handler catches and prints "skip". The loop continues to the next element and then "end" prints. The try/except is inside the loop, so a single bad element does not stop iteration.
Premium Content
Unlock Output Questions - Part 2 and all premium lessons with a subscription.
From ₹199.99/year — See plans