Python Output-Based Questions: 13 Solved Snippets

Trace 13 compact Python snippets on references, slices and mutation. Each example gives the output first and then explains the object-level reason.

KnowledgeGate Team

Exam prep & CS education

Updated 20 Jul 20265 min read

Python output questions usually probe three behaviours: references, slicing and mutability. The syntax is short, which makes it tempting to answer from instinct. A better method is to mark which names share an object, which operations create a new object and which operations mutate one in place.

Predict the output of each snippet below before you read its explanation, and write the prediction down. A guess you never committed to is easy to rewrite once the answer is on the screen.

Lists and references

1. Two names, one list

a = [1, 2]
b = a
b.append(3)
print(a, b)

Output:

[1, 2, 3] [1, 2, 3]

Assignment does not copy the list. Both names refer to the same object, so an append through b is visible through a.

2. Shallow copy versus deep copy

import copy

a = [[1], [2]]
b = copy.copy(a)
c = copy.deepcopy(a)
a[0].append(9)
print(b, c)

Output:

[[1, 9], [2]] [[1], [2]]

The shallow copy creates a new outer list but shares the inner lists. A full slice, a[:], makes the same kind of copy. The deep copy recursively creates independent nested objects, so c does not see the append.

3. List multiplication trap

grid = [[0] * 3] * 2
grid[0][1] = 7
print(grid)

Output:

[[0, 7, 0], [0, 7, 0]]

Multiplication repeats references to one inner list, not two independent rows. A safe construction is [[0] * 3 for _ in range(2)].

4. append versus extend

x = [1, 2]
y = [1, 2]
x.append([3, 4])
y.extend([3, 4])
print(x)
print(y)

Output:

[1, 2, [3, 4]]
[1, 2, 3, 4]

append adds its argument as one new element. extend iterates over its argument and adds each element separately.

a and b arrows point to one list object [1, 2, 3], while c = a[:] points to a separate list holding the same values.

Slicing output questions

5. Negative indices

a = [10, 20, 30, 40]
print(a[-1], a[-3])

Output:

40 20

Index -1 selects the last element. Counting backwards, -3 selects 20.

6. A positive step

a = list(range(8))
print(a[1:7:2])

Output:

[1, 3, 5]

The slice starts at index 1 and stops before index 7. A step of 2 selects indices 1, 3 and 5.

7. Slice assignment can change length

a = [1, 2, 3, 4]
a[1:3] = [8, 9, 10]
print(a)

Output:

[1, 8, 9, 10, 4]

The target slice contains 2 and 3, and both are replaced. The replacement iterable has three elements, so the list grows by one.

8. Reversing with a slice

s = "gate"
print(s[::-1])

Output:

etag

Omitted bounds cover the full string, while a step of -1 walks backwards. The result is a new string because strings are immutable.

Mutability and function defaults

9. Mutable default argument

def add(value, bucket=[]):
    bucket.append(value)
    return bucket

print(add(1))
print(add(2))

Output:

[1]
[1, 2]

The default list is created once when the function is defined, not on every call. Use None as the default and create a new list inside when each call needs fresh state.

10. An immutable tuple can contain a mutable list

t = ([1, 2], "ok")
t[0].append(3)
print(t)

Output:

([1, 2, 3], 'ok')

Tuple immutability prevents rebinding a tuple position. It does not freeze a mutable object already referenced from that position.

11. String methods return new strings

s = "gate"
t = s.upper()
print(s, t)

Output:

gate GATE

upper() cannot modify s because strings are immutable. It returns a new string, which is bound to t.

is, == and the small-integer sting

12. Equality versus identity

a = [1, 2]
b = [1, 2]
c = a
print(a == b, a is b, a is c)

Output:

True False True

== compares values, so the two separately created lists are equal. is compares object identity, so only c, which was assigned from a, is identical to a.

13. The small-integer sting

a = int("256")
b = int("256")
c = int("257")
d = int("257")
print(a is b, c is d)

Output:

True False

CPython keeps one cached object for every small integer from -5 to 256, so the two 256 values are the same object while the two 257 values are not. That boundary is an implementation detail rather than a rule of the language, and it shifts with how the integers are written: as plain literals in a single block, a = 257 and b = 257 would report True, because the compiler stores one shared constant for both. Only a == b is the portable value test.

Well-written questions either state the implementation, use an explicit alias as in snippet 12, or ask which operator is semantically correct. In production code, use is for singletons such as None, and == for numeric or container values.

How tests and vivas use these patterns

Placement tests compress these ideas into a few lines and ask for the exact output. Vivas follow with “why?”, which is where words such as alias, shallow copy, mutable and identity earn their keep. Three shapes cover most of what gets asked: a mutation that reaches a second name through a shared object, an operation that quietly builds a new object instead of changing the old one, and state that survives a call because it was created once at definition time. Every snippet above is one of those three wearing different syntax.

The Coding and CS fundamentals guide places these snippets in a wider interview sequence, and Data Structures MCQs adds practice on representation and operation costs.

The KnowledgeGate question bank holds about 500 Python questions of this kind. Use the Python programming course to build the concepts in order, then come back to output questions and predict before you run anything.

The short version

When checking an answer, name the object that changed and whether the operation mutated it or created a new one. The next time you see a short snippet, draw names and objects before tracing statements.

Use a three-column rough trace if the code is dense: statement, names-to-objects, and visible value. This separates rebinding from mutation and prevents a later print call from being evaluated against an earlier state.

Run the snippet only after committing your prediction, then explain any mismatch before moving on.

Start from the CS Fundamentals category, practise one group at a time, and explain each answer in one sentence about reference sharing or object creation. That is the habit output questions are testing.