Question bank — Python syntax, data types, control flow
Before we start, three tiny vocabulary anchors so nothing here is a symbol you haven't met:
True or false — justify
Cover the answer, decide true or false, then explain why before revealing.
True and 1 are equal when compared with ==.
bool is a subclass of int, so True == 1 and False == 0. That is why sum([True, True, False]) gives 2, which is handy for counting matches.A tuple can never contain something mutable.
t = ([1,2],); t[0].append(3) works.x = 5; y = x; y = 6 changes x to 6.
y = 6 rebinds the name y to a new object; x still tags the original 5. Reference aliasing only shows through mutation, and ints can't be mutated.Copying a list with b = a[:] protects a completely from changes to b.
copy.deepcopy when the list holds mutable objects (e.g. layer weight lists).0.1 + 0.2 == 0.3 is True in Python.
0.1 + 0.2 is 0.30000000000000004. Never test float equality directly; compare with a tolerance instead.Indentation in Python is just a style choice like in C or Java.
IndentationError or silently changes which block a line belongs to.if predictions: and if len(predictions) > 0: always behave the same.
if predictions: is more general (works on any iterable) and is the Pythonic form. They differ if predictions is None, where the first is false and the second raises TypeError.None == False evaluates to True.
None is its own singleton; it is falsy (acts false in an if) but it is not equal to False. None == False is False, while bool(None) is False.An int in Python can overflow like in C.
int has arbitrary precision; it grows to fit any whole number limited only by memory. It is float (fixed 64-bit) that hits precision limits.Adding a float and an int raises a type error.
5 + 2.0 gives 7.0. Python only refuses conversions between incompatible kinds (like str and int), not between numbers.Spot the error
Read the snippet, name what breaks and why.
msg = "Epoch " + 5
TypeError — Python is strongly typed and will not implicitly turn 5 into text. Fix: "Epoch " + str(5) or use an f-string f"Epoch {5}".steps = 1000 / 32 then feeding steps where an integer count is needed.
/ returns a float (31.25), and you cannot run a fractional number of batch steps. Use floor division // to get 31.if acc > 0.95:
print("done")
save()::: IndentationError: unexpected indent — save() is indented deeper than the sibling print with no reason (no new block opened). All lines in one block must align.
weights = [0.5, 0.3]
backup = weights
backup[0] = 0.9Now weights[0] is...
0.9, not 0.5 — backup is a reference to the same list, so mutating through one name is visible through the other. backup = weights.copy() would isolate them.def f():
total += 1
total = 0
f()::: UnboundLocalError — assigning to total inside f marks it local to f for the whole function, so += 1 reads a local that was never set. Add global total (or better, pass and return it).
for x in range(10):
pass
print(x)Is x defined after the loop?
9. Loop variables leak into the surrounding scope in Python (unlike comprehensions). This can silently clobber an outer variable named x.even = [x**2 for x in range(10) if x % 2 = 0]
SyntaxError — = is assignment; the comparison needs ==. The filter clause must be a boolean expression.d = {}
value = d["lr"]::: KeyError: 'lr' — indexing a missing key raises, it does not return None. Use d.get("lr") (returns None) or d.get("lr", default) for a safe fallback.
Why questions
Cover the answer and try to reason it out first.
Why does Python use explicit type conversion instead of auto-coercing everything?
int would truncate every value and quietly destroy a model; forcing int(...) makes the loss a deliberate choice.Why is a tuple preferred over a list for something like input_shape=(28, 28, 1)?
dict key (lists can't, tuples can).Why does dict lookup being "O(1)" matter for storing hyperparameters or feature mappings?
Why does a list comprehension often run faster than the equivalent for + append?
.append method calls of the manual loop.Why does steps_per_epoch = dataset_size // batch_size use floor division rather than rounding?
Why does Python search names in the LEGB order (Local → Enclosing → Global → Built-in)?
learning_rate should shadow a global one — inner scopes override outer ones, and only if nothing matches anywhere do you get NameError.Why is checking if my_list: considered more Pythonic than if len(my_list) != 0:?
Edge cases
The scenarios the happy path skips.
What does range(0, 100, 32) actually produce, and does it include 100?
[0, 32, 64, 96] — range stops before the end value, so 100 is excluded. The last batch (96–99) is a partial batch of 4, which your loop must be ready to handle.What does int(3.7) give — 3 or 4?
3 — int() truncates toward zero, it does not round. int(-3.7) gives -3 for the same reason. Use round() if you actually want nearest-integer.What happens with while condition: if the condition is True on entry and nothing inside ever changes it?
while re-checks the condition every pass, so without a break or a change to the condition variable it never exits. This is the classic "training never stops" bug.What is the boolean value of an empty string "", empty dict {}, 0, and 0.0?
False in an if. So if 0.0: skips its block, which can hide bugs when a legitimate zero (e.g. a zero loss or zero feature) is treated as "missing".If a for loop's iterable is empty, does the loop body run at all?
else, if present). No error is raised.Does an if/elif chain evaluate every condition, or stop early?
elif/else. That is why order matters: a broad condition placed first can mask a narrower one below it.What is special about None compared to other falsy values like 0 or ""?
None is a unique singleton meaning "no value at all" (missing data, uninitialised weight), distinct from a real zero. Test it with is None, never == None, because identity is exact and faster.Recall Self-check before you move on
Can you explain, in one breath each: (a) why b = a[:] still isn't safe for nested lists, (b) why True + True == 2, (c) why floats fail ==, and (d) what range(0, 10, 3) excludes?
If any of these felt shaky, revisit the matching item above — then head to NumPy arrays and vectorization where these type and reference rules quietly power every array operation.