Lists & Slicing Interview Questions & Answers

5 questions Updated 2026-06-18

Python interview questions on lists vs arrays, slicing semantics and negative steps, append vs extend vs insert, comprehensions, and sort vs sorted.

A list is Python's built-in, dynamically-sized, heterogeneous container — it can hold objects of any type because each slot stores a reference to a boxed Python object. The standard-library array.array (and NumPy's ndarray) is homogeneous and typed, storing raw C values contiguously, which is far more memory-efficient for large numeric data.

from array import array
nums = [1, 2, "three"]      # list — mixed types allowed
typed = array("i", [1, 2, 3])  # array — all C ints, compact
typed.append("x")           # TypeError — type-checked

import sys
sys.getsizeof([1, 2, 3])    # bigger: stores pointers
sys.getsizeof(array("i", [1, 2, 3]))  # smaller: packed ints

Rule of thumb: reach for a plain list for general-purpose, mixed-type collections; use array or NumPy when you have large amounts of uniform numeric data and care about memory or vectorized speed.

A slice is lst[start:stop:step]. start is inclusive, stop is exclusive, and any part can be omitted (defaults: start of list, end of list, step 1). A negative step walks the list backwards, and when it's negative the defaults for start/stop flip to the end and the beginning.

a = [0, 1, 2, 3, 4, 5]
a[1:4]      # [1, 2, 3]   — stop is exclusive
a[:3]       # [0, 1, 2]   — omitted start = 0
a[::2]      # [0, 2, 4]   — every other element
a[::-1]     # [5, 4, 3, 2, 1, 0]  — reversed copy
a[4:1:-1]   # [4, 3, 2]   — backwards, stop exclusive

Slicing never raises for out-of-range indices (a[10:20] is just []), unlike single-element indexing. Remember a[::-1] is the idiomatic way to get a reversed shallow copy.

append(x) adds a single item to the end in amortized O(1). extend(iterable) adds each element of an iterable to the end (also amortized O(1) per element). insert(i, x) places an item at index i, which is O(n) because every following element must shift right.

a = [1, 2, 3]
a.append([4, 5])   # [1, 2, 3, [4, 5]]  — the LIST is one element
a = [1, 2, 3]
a.extend([4, 5])   # [1, 2, 3, 4, 5]    — unpacks the iterable
a.insert(0, 99)    # [99, 1, 2, 3, 4, 5] — O(n) shift

The classic trap: append([4, 5]) nests the whole list as one item, whereas extend([4, 5]) merges its elements. Avoid insert(0, …) in a loop — it's O(n) each time; use collections.deque for fast front insertion.

Usually yes. A comprehension runs its iteration in optimized C-level bytecode and avoids the repeated list.append attribute lookup and method call that a manual loop incurs, so it's typically 20–40% faster as well as more concise. It also creates the loop variable in its own scope, so it doesn't leak.

# manual loop — explicit append each iteration
squares = []
for n in range(1000):
    squares.append(n * n)

# comprehension — faster and clearer
squares = [n * n for n in range(1000)]

Use a comprehension when you're building a list from an expression. But if the body has side effects or grows complex (nested conditionals, multiple statements), a readable for loop is the better choice — clarity beats a small speed win.

list.sort() sorts a list in place and returns None — it mutates the original and only works on lists. sorted(iterable) returns a new sorted list and leaves the input untouched, accepting any iterable (tuples, sets, generators, dict keys).

nums = [3, 1, 2]
result = nums.sort()        # result is None! nums is now [1, 2, 3]

original = (3, 1, 2)
new = sorted(original)      # new = [1, 2, 3], original unchanged
sorted(["bb", "a"], key=len, reverse=True)  # ['bb', 'a']

Both are stable (equal elements keep their order) and run in O(n log n) (Timsort). Watch the gotcha: x = mylist.sort() leaves x as None. Use sort() to save memory when you don't need the original; use sorted() when you must preserve it or are sorting a non-list iterable.

Practice tests are coming soon

Get notified when interactive mock interviews and quizzes launch.