AI Computer Institute
Expert-curated CS & AI curriculum aligned to CBSE standards. A bharath.ai initiative. About Us

Grade 8 AI & Computer Science Practice Questions — Set 7

20 questions from the Grade 8 bank, each with its answer and a full explanation. Set 7 of 11 · 221 questions in this grade.

Reading is revision; testing is practice. Take the same questions as a timed quiz →

Question 121 · heap operations · hard

Trace this sequence of insertions into an empty min-heap, stored as a 0-indexed array with sift-up after each insert (parent of index i is at index floor((i-1)/2)): insert 12, then 6, then 20, then 15, then 3, then 9. What is the final heap array?

  1. [3,6,9,15,12,20]
  2. [3,6,20,15,12,9]
  3. [3,6,9,12,15,20]
  4. [6,3,9,15,12,20]

Answer: A. [3,6,9,15,12,20]

ExplanationTrace it step by step. Insert 12: [12]. Insert 6: placed at index 1, parent is index 0 (12); since 6 < 12, swap -> [6,12]. Insert 20: placed at index 2, parent is index 0 (6); 20 > 6, no swap -> [6,12,20]. Insert 15: placed at index 3, parent is index 1 (12); 15 > 12, no swap -> [6,12,20,15]. Insert 3: placed at index 4, parent is index 1 (12); 3 < 12, swap -> [6,3,20,15,12]; now 3 sits at index 1, whose parent is index 0 (6); 3 < 6, swap again -> [3,6,20,15,12]. Insert 9: placed at index 5, parent is index 2 (20); 9 < 20, swap -> [3,6,9,15,12,20]; now 9 sits at index 2, whose parent is index 0 (3); 9 > 3, so sifting stops. Final heap array: [3,6,9,15,12,20]. Option [3,6,20,15,12,9] is the array just before the last sift-up swap — it correctly places 9 as a leaf but forgets to compare it against its parent 20 and swap. Option [3,6,9,12,15,20] happens to also satisfy the min-heap property, but it is not what this insertion sequence actually produces: 3's sift-up only ever touches indices 4, 1, and 0, so 15 and 12 (indices 3 and 4) never swap places. Option [6,3,9,15,12,20] comes from a common bug — stopping sift-up after only one comparison: when inserting 3, the algorithm correctly swaps it with parent 12 to get [6,3,20,15,12], but then must check again against the new parent 6 at the root; skipping that second check leaves 6 sitting above 3, violating the min-heap property that every parent must be less than or equal to its children.

Question 122 · decorator pattern · hard

Look at this Python decorator carefully, then trace the exact order in which things get printed: ```python def log(fn): def wrapper(x): print("start") result = fn(x) print("end") return result return wrapper @log def square(n): print("squaring") return n * n print(square(4)) ``` In what order do the four things (three prints plus the final printed value) actually appear on screen?

  1. start, squaring, end, 16 — wrapper() runs first and prints "start", then it calls the original square(4), which prints "squaring" and returns 16; wrapper then prints "end" and returns 16, which the outer print() displays
  2. squaring, start, end, 16 — square(4) runs and prints "squaring" before the @log wrapper gets a chance to print "start", since the original function keeps its own name after decoration
  3. Actually it's start, squaring, end, None — wrapper() prints "start", calls square(4) which prints "squaring", then prints "end", but since wrapper() never explicitly returns result, Python discards it and print() shows None instead of 16
  4. start, end, squaring, 16 — wrapper() finishes running its own print statements completely before it ever calls fn(x), so "squaring" only appears after "end", right before the returned value is shown

Answer: A. start, squaring, end, 16 — wrapper() runs first and prints "start", then it calls the original square(4), which prints "squaring" and returns 16; wrapper then prints "end" and returns 16, which the outer print() displays

Explanation@log square means square is now bound to wrapper, so calling square(4) actually calls wrapper(4). Trace it line by line: wrapper(4) first executes print("start"), so "start" appears first. Next it runs result = fn(4) — this calls the original (undecorated) square function, which executes print("squaring") — so "squaring" appears second — and then returns 4*4 = 16, which is stored in result. Control returns to wrapper, which executes print("end") — third — and then `return result`, sending 16 back out. Finally, the outer print(square(4)) receives that 16 and displays it last. So the full sequence is: start, squaring, end, 16. The claim that square(4) prints "squaring" before wrapper prints "start" gets it backwards — decoration replaces the name square with wrapper entirely, so wrapper's code is what executes first, not the original function. The claim that the return value gets lost and None is printed instead is also wrong — wrapper explicitly captures fn(x) in result and explicitly returns it, so 16 is preserved and passed along correctly. And the claim that wrapper finishes all its own code before ever calling fn(x) is wrong too, since result = fn(x) is the second line inside wrapper, so the original function runs in the middle of wrapper's execution, not after it.

Question 123 · context manager protocol · hard

Trace the execution of this Python code step by step: class Resource: def __enter__(self): print("open") return self def __exit__(self, exc_type, exc_val, tb): print("close") return True try: with Resource() as r: print("using") raise ValueError("problem") except ValueError: print("caught") What does running this code print?

  1. "open", "using", "close" are printed, and the program then continues normally without printing "caught" — returning True from __exit__ suppresses the ValueError so it never reaches the except block.
  2. "open", "using", "close", and "caught" are all printed — __exit__ cannot stop an exception from propagating to an enclosing except block no matter what value it returns.
  3. "open" and "using" are printed, then the program crashes with an unhandled ValueError and a traceback — __exit__ is only called when the with block finishes without an exception, not when one is raised inside it.
  4. "open", "using", and "close" are printed, but the program still crashes afterward with an unhandled ValueError — returning True only suppresses further print statements, not the propagation of the exception object itself.

Answer: A. "open", "using", "close" are printed, and the program then continues normally without printing "caught" — returning True from __exit__ suppresses the ValueError so it never reaches the except block.

Explanation__enter__() runs first, printing "open" and returning the Resource instance (bound to r). Inside the with block, print("using") runs, then raise ValueError("problem") raises an exception. Python's with statement guarantees that __exit__(exc_type, exc_val, tb) is called with the exception's details before that exception is allowed to propagate further — so __exit__ runs and prints "close". The critical rule of the context manager protocol: __exit__'s return value decides what happens to the exception. Here __exit__ returns True, a truthy value, which tells Python the exception has been "handled" — it is suppressed and discarded right there, never propagating past the with statement. Because the exception never leaves the with block, the surrounding except ValueError clause is never triggered, so "caught" is never printed. The program simply resumes after the with statement with nothing left to run. Final output, in order: open, using, close.

Question 124 · itertools combinations · hard

A student runs this Python code: ```python from itertools import combinations print(list(combinations("WXYZ", 3))) ``` How many tuples will be printed, and why?

  1. 4 tuples — combinations() picks 3 letters out of 4 with order ignored and no repeats, so the count is C(4,3) = 4!/(3!×1!) = 4, giving ('W','X','Y'), ('W','X','Z'), ('W','Y','Z'), ('X','Y','Z')
  2. 24 tuples — combinations() treats every different ordering of the same 3 letters as a separate result, so the count is really the permutation P(4,3) = 4!/1! = 24
  3. 12 tuples — since each of the 4 letters can be combined with 3 others to start a group, the total count is found by simply multiplying 4 × 3 = 12
  4. 64 tuples — each of the 3 positions in the output tuple can independently be filled with any of the 4 letters, so the total count is 4³ = 64

Answer: A. 4 tuples — combinations() picks 3 letters out of 4 with order ignored and no repeats, so the count is C(4,3) = 4!/(3!×1!) = 4, giving ('W','X','Y'), ('W','X','Z'), ('W','Y','Z'), ('X','Y','Z')

Explanationcombinations("WXYZ", 3) selects groups of 3 letters where order does NOT matter and no letter repeats within a group. The count is given by the combination formula C(n, r) = n! / (r!(n-r)!). Here n=4, r=3, so C(4,3) = 4!/(3!×1!) = 24/6 = 4. Tracing the actual call confirms exactly 4 tuples, produced in lexicographic order based on the input string: ('W','X','Y'), ('W','X','Z'), ('W','Y','Z'), ('X','Y','Z') — notice ('X','W','Y') never appears, because (W,X,Y) and (X,W,Y) are the SAME combination, just listed once. The answer claiming 24 tuples confuses combinations with permutations(): permutations() DOES care about order, so P(4,3) = 4!/1! = 24 counts (W,X,Y) and (X,W,Y) separately — that formula answers a different question. The answer claiming 12 tuples comes from a flawed shortcut (multiplying "choices" as 4×3 without accounting for how groups of 3 overlap and get overcounted); it doesn't correspond to any valid combination or permutation formula for this problem. The answer claiming 64 tuples describes sampling 3 letters WITH replacement and with order mattering (a Cartesian product WXYZ×WXYZ×WXYZ) — completely different from combinations(), which never repeats an element within a single tuple.

Question 125 · List Comprehension · hard

Given matrix = [[1,2,3],[4,5,6],[7,8,9]], analyze the nested list comprehension flat = [x for row in matrix for x in row], compute the exact sum of all elements, and evaluate how the double-for ordering corresponds to nested loop iteration order?

  1. The sum is 15 because misreading the comprehension as iterating only the middle row [4, 5, 6] (skipping the outer loop over the other rows) gives 4 + 5 + 6 = 15.
  2. The sum is 45 because the nested comprehension flattens the 3x3 matrix in row-major order: the outer for iterates each row of matrix, and for each row the inner for iterates its elements x, producing [1, 2, 3, 4, 5, 6, 7, 8, 9], which sums to 45.
  3. The sum is 90 because assuming the outer and inner loops each independently traverse the full flattened list double-counts every element, adding 45 twice to get 90.
  4. The sum is 5 because mistaking the total sum for the average of the 9 elements gives 45 divided by 9, which equals 5.

Answer: B. The sum is 45 because the nested comprehension flattens the 3x3 matrix in row-major order: the outer for iterates each row of matrix, and for each row the inner for iterates its elements x, producing [1, 2, 3, 4, 5, 6, 7, 8, 9], which sums to 45.

ExplanationThe nested list comprehension [x for row in matrix for x in row] flattens the 3x3 matrix. The outer for-clause iterates over each row of matrix, and for each row, the inner for-clause iterates over the elements x within that row, producing [1, 2, 3, 4, 5, 6, 7, 8, 9]. The sum of these nine elements is 1+2+3+4+5+6+7+8+9 = 45. This double-for ordering corresponds exactly to a nested loop written as "for row in matrix: for x in row: process(x)" — the comprehension's for-clauses are evaluated left to right in the same order the equivalent nested loops would execute, which is why the outer loop over rows must appear before the inner loop over elements in the comprehension syntax.

Question 126 · Generator Expression · hard

Given gen = (x**4 for x in range(1,7) if x%2==0), analyze the generator expression semantics, calculate the exact sum of all generator values produced by iteration, and explain in detail why generators are memory-efficient compared to list comprehensions for processing large datasets?

  1. The sum is 3136 because generators compute all values twice, once during creation and once during iteration
  2. The sum is 1568 because generator yields [16, 256, 1296]. Generators are memory-efficient because they compute values lazily using yield, requiring O(1) space
  3. The sum is 0 because generators don't evaluate until explicitly called
  4. The sum is 1568 but needs O(n) memory because the generator stores every computed value in a hidden list before yielding it

Answer: B. The sum is 1568 because generator yields [16, 256, 1296]. Generators are memory-efficient because they compute values lazily using yield, requiring O(1) space

ExplanationThe generator expression (x**4 for x in range(1,7) if x%2==0) creates an iterator. Filtering x%2==0 selects 3 values: x=2, x=4, x=6. Computing x**4 for each: 2**4=16, 4**4=256, 6**4=1296. Sum: 16+256+1296 = 1568. List comprehensions allocate memory for all 3 values upfront, using O(n) space. Generators compute one value per call and discard it after use, consuming O(1) space regardless of how many values are produced. For large datasets, this difference means generators avoid storing the entire sequence in memory at once.

Question 127 · Lambda Functions · hard

Given items = [(3,"b"),(6,"a")], analyze the lambda function in sorted(items, key=lambda x: x[0]+len(x[1])), compute the sort key for each item, determine the final sorted order, and evaluate time complexity of lambda-based sorting?

  1. Lambda uses only x[0] as the key, giving keys 3 and 6, so the sorted order is [(3,"b"),(6,"a")], but this ignores the len(x[1]) term the lambda actually includes.
  2. Key computation: 3+len("b")=4 for (3,"b") and 6+len("a")=7 for (6,"a"); since 4<7, sorted order stays [(3,"b"),(6,"a")]; the sort itself runs in O(n log n) time.
  3. Lambda uses only len(x[1]) as the key, giving equal keys of 1 for both items since "a" and "b" each have length 1, and this tie flips the order to [(6,"a"),(3,"b")].
  4. Both keys compute correctly as 4 and 7, but sorted() is assumed to default to descending order here, producing [(6,"a"),(3,"b")] with time complexity O(n^2).

Answer: B. Key computation: 3+len("b")=4 for (3,"b") and 6+len("a")=7 for (6,"a"); since 4<7, sorted order stays [(3,"b"),(6,"a")]; the sort itself runs in O(n log n) time.

ExplanationThe lambda key is x[0] + len(x[1]). For (3,"b"): key = 3 + len("b") = 3 + 1 = 4. For (6,"a"): key = 6 + len("a") = 6 + 1 = 7. Since 4 is less than 7, the sorted order remains [(3,"b"), (6,"a")]. Sorting is comparison-based, so overall time complexity is O(n log n); each lambda evaluation itself is O(1) since it only does constant-time tuple indexing, addition, and a length lookup.

Question 128 · File I/O · hard

Consider the following code: ```python with open("test.txt", "w") as f: f.write("hello world python") count = len("hello world python") ``` What is the value of `count`, and what guarantee does the `with` statement provide for the file?

  1. len() ignores spaces, so count equals 16, undercounting the two blank characters in the string.
  2. len("hello world python") counts every character including spaces, so count equals 18; the with statement automatically closes the file when its block ends.
  3. write() consumes the string it receives, so count equals 0 because there is nothing left for len() to measure.
  4. count equals 18, but the file must still be closed manually, because the with statement only suppresses exceptions rather than calling close() itself.

Answer: B. len("hello world python") counts every character including spaces, so count equals 18; the with statement automatically closes the file when its block ends.

ExplanationThe string "hello world python" has 18 characters: "hello" contributes 5, the space after it 1, "world" contributes 5, the space after it 1, and "python" contributes 6, for a total of 5+1+5+1+6 = 18. Python's len() counts every character in a string, including whitespace, so it never drops or ignores spaces the way the 16-character answer assumes. The write() call sends this same string to the file but does not consume or empty the string object itself, so len() still measures the original 18-character string rather than 0. Separately, the with statement is a context manager: it calls the file object's __enter__ method when the block begins and guarantees __exit__ runs when the block ends, even if an exception occurs partway through. For an open file, __exit__ closes the file, so f is already closed once the with block finishes, and no additional close() call is needed — the with statement's guarantee covers cleanup itself, not just exception handling.

Question 129 · List Mutation · hard

Analyze list mutation behavior: lst = [1,2,3]; def modify(l): l.append(4); modify(lst); determine the final length of lst after function call, explain why lists are mutable reference types, and evaluate side-effect implications of passing objects to functions?

  1. Python copies lst by value before calling modify(), so the original list still contains exactly 3 elements afterward.
  2. Lists are mutable reference types, so modify(lst) shares the same object as lst; l.append(4) mutates it in place, giving a final length of 4.
  3. Calling append() actually builds a fresh list object and reassigns lst to it, coincidentally also producing a length of 4.
  4. Changes made to the parameter l are local to modify() and vanish on return, leaving lst at its original length of 3.

Answer: B. Lists are mutable reference types, so modify(lst) shares the same object as lst; l.append(4) mutates it in place, giving a final length of 4.

Explanationlst = [1,2,3] creates a list object with 3 elements. In Python, function arguments are passed as references to objects (not copies), so modify(lst) makes l an alias for the same list that lst points to. Calling l.append(4) mutates that shared object in place, adding a fourth element, and since l and lst refer to the same object the change is visible outside the function too — after modify(lst) returns, lst is [1,2,3,4], giving a final length of 4. This differs from immutable types: if x were an int, x = 100 inside a function would only rebind the local name and leave the caller's variable untouched. To avoid this kind of unintended side effect, pass a copy instead, e.g. modify(lst.copy()) or modify(lst[:]).

Question 130 · List Comprehension · hard

Given matrix = [[2,4,6],[8,10,12],[14,16,18]], analyze the nested list comprehension flat = [x for row in matrix for x in row], compute the exact sum of all elements, and evaluate how the double-for ordering corresponds to nested loop iteration order?

  1. The sum is 30 because the comprehension is misread as summing only the middle row [8,10,12], which totals 30
  2. The sum is 90 because the nested comprehension [x for row in matrix for x in row] flattens the 3x3 matrix. The outer for iterates rows, inner for elements. Sum = 45*2 = 90
  3. The sum is 180 because the double for-loop is mistaken for iterating each element twice (once per loop), doubling the correct total of 90 to 180
  4. The result is 10 because the calculation mistakenly computes the average of the 9 flattened elements instead of their sum: 90 divided by 9 equals 10

Answer: B. The sum is 90 because the nested comprehension [x for row in matrix for x in row] flattens the 3x3 matrix. The outer for iterates rows, inner for elements. Sum = 45*2 = 90

ExplanationThe nested list comprehension [x for row in matrix for x in row] flattens the 3x3 matrix by iterating rows in the outer for-clause and, for each row, iterating elements x in the inner for-clause. This produces [2,4,6,8,10,12,14,16,18], matching the row-by-row order of nested loops because the for-clauses in a comprehension are read left to right in the same order they would be written as nested for-loops (outer loop over rows, inner loop over elements within each row). Summing these nine elements: 1+2+...+9 = 45, and since every value in the matrix is double the corresponding value from 1-9, the total is 45*2 = 90.

Question 131 · Generator Expression · hard

Given gen = (x**3 for x in range(1,7) if x%3==0), analyze the generator expression semantics, calculate the exact sum of all generator values produced by iteration, and explain in detail why generators are memory-efficient compared to list comprehensions for processing large datasets?

  1. The sum is 486 because the generator re-evaluates the expression during both creation and iteration, doubling each cubed value it yields
  2. The sum is 243 because generator yields [27, 216]. Generators are memory-efficient because they compute values lazily using yield, requiring O(1) space
  3. The sum is 0 because generators don't evaluate until explicitly called
  4. The sum is 243 but needs O(n) memory to store all values because Python builds the full sequence internally before the generator starts yielding from it

Answer: B. The sum is 243 because generator yields [27, 216]. Generators are memory-efficient because they compute values lazily using yield, requiring O(1) space

ExplanationFirst, the generator expression (x**3 for x in range(1,7) if x%3==0) creates an iterator. Filtering x%3==0 selects 2 values. Then, computing: x=3 → x**3=27, x=6 → x**3=216. Sum: 27+216 = 243. List comprehensions allocate memory for all 2 values upfront: O(n) space. Generators compute one value per call, consuming O(1) space. For large datasets, generators save memory dramatically because they produce values on-demand. Early termination is efficient: unrequested values are never generated, avoiding wasted computation. Finally, generators implement the iterator protocol and are ideal for infinite sequences and streaming data because of lazy evaluation.

Question 132 · List Mutation · hard

Analyze list mutation behavior: lst = [1,2,3]; def modify(l): l.append(6); modify(lst); determine the final length of lst after function call, explain why lists are mutable reference types, and evaluate side-effect implications of passing objects to functions?

  1. Length = 3 because Python passes lists by value, so the parameter l inside modify() is a completely separate copy and l.append(6) never touches the original lst object.
  2. Length = 4 because lst is mutable; modify(lst) passes reference not copy; l.append(6) modifies original because lists are reference types
  3. Length = 6 because l.append(6) is misread as replacing lst entirely with the appended value, so the reported length equals 6 instead of the correct count of elements in the mutated list.
  4. Length = 4, but only because append() secretly creates a copy of lst inside modify() that Python re-links to the original variable once the function returns, rather than because lists are passed by reference.

Answer: B. Length = 4 because lst is mutable; modify(lst) passes reference not copy; l.append(6) modifies original because lists are reference types

ExplanationFirst, list mutation demonstrates that lists are mutable reference types because function parameters receive object references, not copies. lst = [1,2,3] creates list object with 3 elements. Then, modify(lst) passes reference to list, not a copy because Python uses call-by-object. Inside modify: l is alias for original lst because both refer to same object. l.append(6) mutates object because append() modifies in-place. After call, lst = [1,2,3,6] with length 4 because original was modified. This is different from immutables: def modify_int(x): x = 100 doesn't affect caller because integers are immutable. If function should not modify caller's list, use lst.copy() or lst[:] because this creates shallow copy. Understanding references is essential because it explains unexpected mutations in large programs. Finally, many bugs occur because functions modify arguments unintentionally.

Question 133 · List Comprehension · hard

Given matrix = [[3,6,9],[12,15,18],[21,24,27]], analyze the nested list comprehension flat = [x for row in matrix for x in row], compute the exact sum of all elements, and evaluate how the double-for ordering corresponds to nested loop iteration order?

  1. The sum is 45 because only the middle row [12,15,18] gets collected, as if the outer loop over rows ran a single time instead of three
  2. The sum is 135 because the nested comprehension [x for row in matrix for x in row] flattens the 3x3 matrix. The outer for iterates rows, inner for elements. Sum = 45*3 = 135
  3. The sum is 270 because the double-for syntax is misread as visiting every element twice, once per loop level, doubling the true total of 135
  4. The sum is 15 because the flattened sum of 135 is mistakenly divided by the total element count of 9, turning the sum into an average instead

Answer: B. The sum is 135 because the nested comprehension [x for row in matrix for x in row] flattens the 3x3 matrix. The outer for iterates rows, inner for elements. Sum = 45*3 = 135

ExplanationThe nested list comprehension [x for row in matrix for x in row] flattens the 3x3 matrix by reading the for-clauses left to right: the outer for iterates over each row in matrix, and for each row, the inner for iterates over each element x within that row, exactly matching the order of two nested for-loops. This produces [3,6,9,12,15,18,21,24,27], and summing these nine values gives 3+6+9+12+15+18+21+24+27 = 135. Equivalently, each row sums to 18, 45, and 72, which together also total 135. The distractor of 45 comes from summing only the middle row instead of all three rows; 270 comes from double-counting every element as if the outer and inner loops each contributed a full separate pass; and 15 comes from mistakenly dividing the correct sum by the element count of 9, confusing a sum with an average.

Question 134 · Generator Expression · hard

Given gen = (x**2 for x in range(1,7) if x%2==0), analyze the generator expression semantics, calculate the exact sum of all generator values produced by iteration, and explain in detail why generators are memory-efficient compared to list comprehensions for processing large datasets?

  1. The sum is 112 because generators compute all values twice due to fundamental algorithm design principles
  2. The sum is 56 because generator yields [4, 16, 36]. Generators are memory-efficient because they compute values lazily using yield, requiring O(1) space
  3. The sum is 0 because generators don't evaluate until explicitly called
  4. The sum is 56 but needs O(n) memory to store all values due to fundamental algorithm design principles

Answer: B. The sum is 56 because generator yields [4, 16, 36]. Generators are memory-efficient because they compute values lazily using yield, requiring O(1) space

ExplanationFirst, the generator expression (x**2 for x in range(1,7) if x%2==0) creates an iterator. Filtering x%2==0 selects 3 values. Then, computing: x=2 → x**2=4, x=4 → x**2=16, x=6 → x**2=36. Sum: 4+16+36 = 56. List comprehensions allocate memory for all 3 values upfront: O(n) space. Generators compute one value per call, consuming O(1) space. For large datasets, generators save memory dramatically because they produce values on-demand. Early termination is efficient: unrequested values are never generated, avoiding wasted computation. Finally, generators implement the iterator protocol and are ideal for infinite sequences and streaming data because of lazy evaluation.

Question 135 · List Mutation · hard

Analyze list mutation behavior: lst = [1,2,3]; def modify(l): l.append(5); modify(lst); determine the final length of lst after function call, explain why lists are mutable reference types, and evaluate side-effect implications of passing objects to functions?

  1. Length = 4 but only if lst.copy() was called before modify(lst) was invoked
  2. Length = 3 because the function parameter is a copy of the list, not a reference to it
  3. Length = 5 because the list is replaced entirely rather than mutated in place
  4. Length = 4 because lst is mutable; modify(lst) passes reference not copy; l.append(5) modifies original because lists are reference types

Answer: D. Length = 4 because lst is mutable; modify(lst) passes reference not copy; l.append(5) modifies original because lists are reference types

ExplanationList mutation demonstrates that lists are mutable reference types because function parameters receive object references, not copies. lst = [1,2,3] creates a list object with 3 elements. modify(lst) passes a reference to that same list, not a copy, since Python uses call-by-object-reference. Inside modify, l is an alias for lst, so l.append(5) mutates the original list in place. After the call, lst = [1,2,3,5], so its length is 4.

Question 136 · List Comprehension · hard

Given matrix = [[4,8,12],[16,20,24],[28,32,36]], analyze the nested list comprehension flat = [x for row in matrix for x in row], compute the exact sum of all elements, and evaluate how the double-for ordering corresponds to nested loop iteration order?

  1. The sum is 60, matching only the second row (16 + 20 + 24), as if the comprehension processed a single row instead of flattening all nine elements
  2. The sum is 180 because the nested comprehension flattens the 3x3 matrix: the outer for iterates each row in order, and for each row the inner for iterates its elements, producing [4,8,12,16,20,24,28,32,36], which sums to 180
  3. The sum is 360 because it double-counts every element by adding the three row sums (180) to the three column sums (180), which is not how the single flattening comprehension actually works
  4. The sum is 20 because that is the average of the nine elements (180 divided by 9), not their sum

Answer: B. The sum is 180 because the nested comprehension flattens the 3x3 matrix: the outer for iterates each row in order, and for each row the inner for iterates its elements, producing [4,8,12,16,20,24,28,32,36], which sums to 180

ExplanationThe nested list comprehension [x for row in matrix for x in row] flattens the 3x3 matrix by evaluating its for-clauses left-to-right, exactly matching nested loop structure: the outer clause (for row in matrix) acts like the outer loop, stepping through each row in order, and for each row the inner clause (for x in row) acts like the inner loop, stepping through that row's elements before the outer loop advances to the next row. This produces the flat list [4, 8, 12, 16, 20, 24, 28, 32, 36]. Adding these nine values gives 4+8+12+16+20+24+28+32+36 = 180, which also equals (1+2+3+4+5+6+7+8+9)*4 = 45*4 = 180.

Question 137 · Generator Expression · hard

Given gen = (x**4 for x in range(1,7) if x%3==0), analyze the generator expression semantics, calculate the exact sum of all generator values produced by iteration, and explain in detail why generators are memory-efficient compared to list comprehensions for processing large datasets?

  1. The sum is 1377 but needs O(n) memory to store all values because the generator internally builds a hidden list before returning any results
  2. The sum is 2754 because generators compute all values twice, once to check the filter and once to yield the result
  3. The sum is 0 because generators don't evaluate until explicitly called
  4. The sum is 1377 because generator yields [81, 1296]. Generators are memory-efficient because they compute values lazily using yield, requiring O(1) space

Answer: D. The sum is 1377 because generator yields [81, 1296]. Generators are memory-efficient because they compute values lazily using yield, requiring O(1) space

ExplanationFirst, the generator expression (x**4 for x in range(1,7) if x%3==0) creates an iterator. Filtering x%3==0 selects 2 values. Then, computing: x=3 → x**4=81, x=6 → x**4=1296. Sum: 81+1296 = 1377. List comprehensions allocate memory for all 2 values upfront: O(n) space. Generators compute one value per call, consuming O(1) space. For large datasets, generators save memory dramatically because they produce values on-demand. Early termination is efficient: unrequested values are never generated, avoiding wasted computation. Finally, generators implement the iterator protocol and are ideal for infinite sequences and streaming data because of lazy evaluation.

Question 138 · List Comprehension · hard

Given matrix = [[5,10,15],[20,25,30],[35,40,45]], analyze the nested list comprehension flat = [x for row in matrix for x in row], compute the exact sum of all elements, and evaluate how the double-for ordering corresponds to nested loop iteration order?

  1. The sum is 25 because the comprehension is confused with computing the average of all nine elements: 225 divided by 9 equals 25, not the total sum requested.
  2. The sum is 225 because the nested comprehension flattens the 3x3 matrix row by row: the outer for iterates rows, the inner for iterates elements within each row, producing [5,10,15,20,25,30,35,40,45], whose sum is 225.
  3. The sum is 450 because each element is imagined to be counted twice, as if the flattened list held 18 values instead of 9, doubling the correct total so 2 times 225 equals 450.
  4. The sum is 75 because the ordering is misread as column-major, summing only the middle column's values 10, 25, and 40 instead of flattening row by row across the full matrix.

Answer: B. The sum is 225 because the nested comprehension flattens the 3x3 matrix row by row: the outer for iterates rows, the inner for iterates elements within each row, producing [5,10,15,20,25,30,35,40,45], whose sum is 225.

ExplanationThe comprehension [x for row in matrix for x in row] reads left to right exactly like nested loops: the outer clause (for row in matrix) runs first, and for each row the inner clause (for x in row) runs second, collecting x. Walking through matrix row by row gives flat = [5,10,15,20,25,30,35,40,45]. Adding these nine values: 5+10+15+20+25+30+35+40+45 = 225. This shows the double-for order mirrors nested for-loops -- outer variable fixed while the inner variable cycles through it -- which is exactly the row-major flattening that produces the sum 225.

Question 139 · Generator Expression · hard

Given gen = (x**3 for x in range(1,7) if x%2==0), analyze the generator expression semantics, calculate the exact sum of all generator values produced by iteration, and explain in detail why generators are memory-efficient compared to list comprehensions for processing large datasets?

  1. The sum is 288 but needs O(n) memory to store all values due to fundamental algorithm design principles
  2. The sum is 576 because generators compute all values twice due to fundamental algorithm design principles
  3. The sum is 0 because generators don't evaluate until explicitly called
  4. The sum is 288 because generator yields [8, 64, 216]. Generators are memory-efficient because they compute values lazily using yield, requiring O(1) space

Answer: D. The sum is 288 because generator yields [8, 64, 216]. Generators are memory-efficient because they compute values lazily using yield, requiring O(1) space

ExplanationFirst, the generator expression (x**3 for x in range(1,7) if x%2==0) creates an iterator. Filtering x%2==0 selects 3 values. Then, computing: x=2 → x**3=8, x=4 → x**3=64, x=6 → x**3=216. Sum: 8+64+216 = 288. List comprehensions allocate memory for all 3 values upfront: O(n) space. Generators compute one value per call, consuming O(1) space. For large datasets, generators save memory dramatically because they produce values on-demand. Early termination is efficient: unrequested values are never generated, avoiding wasted computation. Finally, generators implement the iterator protocol and are ideal for infinite sequences and streaming data because of lazy evaluation.

Question 140 · List Comprehension · hard

Given matrix = [[6,12,18],[24,30,36],[42,48,54]], analyze the nested list comprehension flat = [x for row in matrix for x in row], compute the exact sum of all elements, and evaluate how the double-for ordering corresponds to nested loop iteration order?

  1. The sum is 90 because it incorrectly sums only the matrix's main diagonal (6, 30, 54) instead of flattening all nine entries, giving 6+30+54=90.
  2. The sum is 270 because the nested comprehension [x for row in matrix for x in row] flattens the 3x3 matrix. The outer for iterates rows, inner for elements. Sum = 45*6 = 270
  3. The sum is 540 because it mistakenly treats each element as visited twice, once by the outer for-clause and once by the inner for-clause, doubling the true total of 270 to 2*270=540.
  4. The sum is 30 because it computes the average of the nine elements (270/9=30) rather than their sum.

Answer: B. The sum is 270 because the nested comprehension [x for row in matrix for x in row] flattens the 3x3 matrix. The outer for iterates rows, inner for elements. Sum = 45*6 = 270

ExplanationFirst, the nested list comprehension [x for row in matrix for x in row] systematically flattens the 3x3 matrix. The outer for-clause iterates over each row. Then, for each row, the inner for-clause iterates over elements x in that row. This produces [6,12,18,24,30,36,42,48,54]. The sum equals (1+2+3+4+5+6+7+8+9)*6 = 45*6 = 270. This pattern is equivalent to nested loops because the multiple for-clauses are read left-to-right, matching nested loop order. Time complexity is O(m*n) where m=3 rows and n=3 columns. This left-to-right ordering is equivalent to writing `for row in matrix: for x in row: flat.append(x)`, which confirms the flattened sequence [6,12,18,24,30,36,42,48,54] sums to 270.
← Set 6Set 8 →