IAE Academy

IN THE DA SYLLABUS

Programming in Python

Python for GATE DA is tested as exact-output tracing: you read a short program and say what it prints. The marks are won by knowing how names refer to objects, which types are mutable, how //, %, slicing, dictionaries and sets behave, how scope and default arguments work, and how a recursion unwinds. All behaviour here is Python 3.

10 previous-year questions · 10 solved · 6 practice questions

Names, references and mutability

A Python variable is a name bound to an object; assignment never copies the object. b = a makes two names for one object. Whether that matters depends on the type: immutable types (int, float, bool, str, tuple) can never change in place, so any 'change' rebinds the name to a new object. Mutable types (list, dict, set) can be changed in place, and every name bound to the object sees the change.

Convention: Python 3 semantics throughout. / is true division and // is floor division; integers are unbounded; indexing starts at 0; dictionaries keep insertion order. print separates its arguments with a single space and ends with a newline (sep= and end= change these). The output shown is exactly what appears on screen.

Aliasing versus copying:

a = [1, 2, 3]
b = a            # alias: same object
b.append(4)
print(a, a is b)
c = a[:]         # shallow copy: new list
c.append(5)
print(a, c)

Output:

[1, 2, 3, 4] True
[1, 2, 3, 4] [1, 2, 3, 4, 5]

Strings are immutable, so += rebinds only one name:

s = "abc"
t = s
s += "d"
print(s, t)

Output: abcd abc. A tuple is immutable, but if it holds a mutable object, that inner object can still change:

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

Output: (1, [2, 3, 4]). Assigning x[0] = 9 would raise a TypeError.

Statement

What it does

Is b is a? What is shared?

b = a

binds a second name to the same object

True; everything is shared

b = a[:], b = a.copy(), b = list(a)

shallow copy: new outer list, same inner objects

False; inner objects (e.g. inner lists) are still shared

b = copy.deepcopy(a)

copies the inner objects as well, recursively

False; no mutable object is shared

== compares values, is compares identity (same object). [1, 2] == [1, 2] is True, but [1, 2] is [1, 2] is False because two list displays make two objects. Whether is is true for two equal numbers or strings depends on the Python implementation, so use is only for None or for objects whose identity the program itself sets up. A shallow copy of a list of lists shares its inner lists:

import copy
q = [[1, 2], [3]]
sh = q.copy()
dp = copy.deepcopy(q)
q[0].append(9)
print(sh, dp)

Output: [[1, 2, 9], [3]] [[1, 2], [3]].

EXAM TIP

[[0] * 2] * 2 builds one inner list referenced twice. After g = [[0] * 2] * 2; g[0][0] = 1 the value of g is [[1, 0], [1, 0]]. The comprehension [[0] * 2 for _ in range(2)] builds two separate lists, and the same assignment gives [[1, 0], [0, 0]].

Numbers, operators and precedence

/ is always true division and returns a float (8 / 2 is 4.0, 7 / 2 is 3.5). // is floor division: it rounds toward negative infinity, not toward zero. % is defined so that the identity below always holds, which means the result of % takes the sign of the divisor (or is 0). If either operand is a float, // and % return a float (10.0 // 4 is 2.0, -7.5 % 2 is 0.5). Integers are unbounded in size.

FLOOR DIVISION AND REMAINDER IN PYTHON

Holds for integers with b nonzero; a // b is the floor of the true quotient, so a nonzero remainder takes the sign of b.

Expression

Value

Why

7 // 2

3

floor of 3.5

-7 // 2

-4

floor of -3.5

7 // -2

-4

floor of -3.5

-7 // -2

3

floor of 3.5

7 % 3

1

7 = 3*2 + 1

-7 % 3

2

-7 = 3*(-3) + 2

7 % -3

-2

7 = (-3)*(-3) + (-2)

-7 % -3

-1

-7 = (-3)*2 + (-1)

int(x) on a float truncates toward zero, unlike //. round(x) rounds to the nearest integer and, for an exact half, to the even neighbour. divmod(a, b) returns the pair (a // b, a % b):

print(int(-3.5), -7 // 2, round(2.5), round(3.5), divmod(-7, 2), 10.0 // 4)

Output: -3 -4 2 4 (-4, 1) 2.0.

Operator precedence, highest to lowest

  1. ** (right-associative)

  2. unary +x, -x, ~x

  3. *, /, //, %

  4. +, -

  5. shifts <<, >>

  6. & (bitwise AND; set intersection)

  7. ^ (bitwise XOR; set symmetric difference)

  8. | (bitwise OR; set union)

  9. comparisons <, <=, >, >=, ==, !=, in, not in, is, is not (all one level, and they chain)

  10. not

  11. and

  12. or

Operators on one level group left to right, except **. ** binds tighter than a unary minus on its left but not on its right (2 ** -1 is 0.5):

print(2 ** 3 ** 2)    # 2 ** 9
print(-2 ** 2)        # -(2 ** 2)
print((-2) ** 2)
print(2 ** -1)
print(1 + 2 * 3 ** 2 % 5)

Output:

512
-4
4
0.5
4

The last line: 3 ** 2 = 9, then 2 * 9 = 18 and 18 % 5 = 3 (same level, left to right), then 1 + 3 = 4.

Comparisons chain: a < b > c means (a < b) and (b > c), with b evaluated once. Shifts and bitwise operators sit below + -:

print(1 < 3 > 2, 3 > 2 == 2, (3 > 2) == 2)
print(2 + 3 << 1, 6 & 3 | 4)

Output:

True True False
10 6

3 > 2 == 2 is (3 > 2) and (2 == 2), which is True; with brackets, (3 > 2) == 2 compares True with 2, which is False. 2 + 3 << 1 is 5 << 1 = 10; 6 & 3 | 4 is 2 | 4 = 6.

Truthiness and short-circuit logic: 0, 0.0, '', [], {}, set(), () and None are false; everything else (including the string '0') is true. a or b returns a if a is true, else b; a and b returns a if a is false, else b. They return one of the operands, not necessarily a bool, and they do not evaluate b when a already decides the result:

print(bool([]), bool(0), bool("0"), 0 or 5, 3 and 0, None or "a")

Output: False False True 5 0 a.

EXAM TIP

Floats are binary approximations: 0.1 + 0.2 == 0.3 is False, while 5 == 5.0 is True. Never rely on exact float equality in a trace unless the numbers are exactly representable (such as halves and quarters).

Lists, tuples and strings

Indexing starts at 0; negative indices count from the end (-1 is the last element). A slice s[i:j:k] takes indices i, i+k, ... up to but not including j. Omitted i, j default to the ends in the direction of k. Out-of-range slice bounds are clipped silently (no error), but an out-of-range single index raises IndexError.

L = [0, 1, 2, 3, 4, 5, 6]
print(L[-1], L[1:4], L[::-1], L[::2])
print(L[-3:], L[5:2], L[2:-2], L[10:])

Output:

6 [1, 2, 3] [6, 5, 4, 3, 2, 1, 0] [0, 2, 4, 6]
[4, 5, 6] [] [2, 3, 4] []

Call

Effect

Return value

lst.append(x)

adds x as ONE new last element

None

lst.extend(it)

adds each element of the iterable it

None

lst.insert(i, x)

inserts x before index i

None

lst.pop() / lst.pop(i)

removes and returns the last / i-th element

the element

lst.remove(x)

removes the first element equal to x (ValueError if none)

None

lst.index(x)

finds the first element equal to x (ValueError if none)

its index

lst.count(x)

counts elements equal to x

the count

lst.sort()

sorts in place

None

sorted(lst)

builds a new sorted list

the new list

lst.reverse()

reverses in place

None

append versus extend, and the None trap:

m = [1, 2]
m.append([3, 4])
print(m, len(m))
n = [1, 2]
n.extend([3, 4])
n.extend("ab")
print(n)
w = [3, 1, 2]
r = w.sort()
print(r, w)

Output:

[1, 2, [3, 4]] 3
[1, 2, 3, 4, 'a', 'b']
None [1, 2, 3]

A string is an iterable of characters, so extend("ab") adds 'a' and 'b' separately.

List comprehension [expr for v in iterable if cond] builds a new list; the condition filters, and expr is evaluated for each kept v:

print([i * i for i in range(6) if i % 2 == 0])

Output: [0, 4, 16]. list("abc") is ['a', 'b', 'c']; tuple([1, 2]) is (1, 2); the one-element tuple needs a comma, so (1,) is a tuple while (1) is just the integer 1. Unpacking: a, *b = (1, 2, 3) gives a = 1, b = [2, 3].

Strings are immutable sequences, indexed and sliced exactly like lists. Methods return new strings and never modify the original:

s = "Hello, World"
print(s[1:5], s[::-1], s.lower(), s.find("o"), s.find("z"), s.count("l"))
print(s.replace("l", "L"), s.split(", "), "-".join(["a", "b", "c"]))
print("  hi ".strip() + "|")

Output:

ello dlroW ,olleH hello, world 4 -1 3
HeLLo, WorLd ['Hello', 'World'] a-b-c
hi|

find returns the index of the first occurrence, or -1 if absent (while index would raise an error). x in s tests for a substring: 'a' in "banana" is True.

* repeats a sequence: "ab" * 3 is 'ababab', [1, 2] * 2 is [1, 2, 1, 2]. Strings, lists and tuples compare lexicographically: element by element from the left, and if one runs out first it is the smaller. Characters compare by code point, so every uppercase letter is smaller than every lowercase letter. "abc" < "abd", "Z" < "a", [1, 2] < [1, 3] and (1, 2) < (1, 2, 0) are all True.

NUMBER OF VALUES IN A RANGE

Holds for integers a, b and any nonzero step k, positive or negative; for example len(range(3, 20, 4)) = ceil(17/4) = 5 and len(range(5, 0, -2)) = ceil(2.5) = 3.

EXAM TIP

range(a, b, k) excludes b and has len(range(3, 20, 4)) = 5 (values 3, 7, 11, 15, 19). list(range(5, 0, -2)) is [5, 3, 1]. += on a list extends it in place (so aliases see it) while x = x + [v] builds a new list and rebinds only x.

Dictionaries and sets

A dictionary maps hashable keys to values: numbers, strings, and tuples whose items are all hashable can be keys; lists, dictionaries and sets cannot. Keys are unique, and in Python 3.7+ a dictionary iterates in insertion order. Assigning to an existing key replaces its value but keeps its original position; deleting a key and inserting it again puts it at the end. d[k] raises KeyError if k is missing, whereas d.get(k) returns None and d.get(k, default) returns default. k in d tests keys, not values.

The standard counting idiom:

d = {}
for ch in "banana":
    d[ch] = d.get(ch, 0) + 1
print(d, list(d.keys()), d.get("z"), d.get("z", -1))
for k, v in d.items():
    print(k, v)

Output:

{'b': 1, 'a': 3, 'n': 2} ['b', 'a', 'n'] None -1
b 1
a 3
n 2

The order b, a, n is the order in which each letter first appeared.

Changing the values of existing keys while looping over a dictionary is safe. Adding or deleting a key, so that the dictionary's size changes during the loop, raises RuntimeError: dictionary changed size during iteration. To add or delete keys, loop over a copy of the keys, for k in list(d):.

d = {"a": 1, "b": 2}
for k in d:
    d[k] += 10
print(d)
print(list(d.items()))

Output:

{'a': 11, 'b': 12}
[('a', 11), ('b', 12)]

A set is an unordered collection of distinct hashable elements; duplicates vanish (len({1, 2, 2, 3, 3, 3}) is 3). The empty set must be written set(), since {} is an empty dictionary. s.add(x) adds an element (no effect if present); s.remove(x) raises KeyError if x is absent, while s.discard(x) does not. Set operations:

Operator

Meaning

For A = {1,2,3,4}, B = {3,4,5}

A | B

union

{1, 2, 3, 4, 5}

A & B

intersection

{3, 4}

A - B

difference (in A, not in B)

{1, 2}

B - A

difference the other way

{5}

A ^ B

symmetric difference (in exactly one)

{1, 2, 5}

SET OPERATION SIZES

For finite sets; A △ B is the symmetric difference, written A ^ B in Python. Use these to count len(A | B) or len(A ^ B) without listing the elements.

EXAM TIP

Do not rely on the printed order of a set; a question that needs a definite output will print sorted(s), a length, or a membership test. A dictionary, by contrast, has a guaranteed insertion order.

Control flow

if / elif / else runs the first branch whose condition is true. for v in iterable visits the items in order; range(start, stop, step) produces start, start+step, ... while strictly before stop (after it in the negative direction if step < 0). while cond repeats while cond is true. break leaves the innermost loop; continue skips to its next iteration. A loop's optional else block runs only if the loop finished without break.

Trace this loop with break, continue and else:

for i in range(5):
    if i == 1:
        continue
    if i == 4:
        break
    print(i, end=" ")
else:
    print("done")
print()

Output: 0 2 3 followed by a newline. The else is skipped because break fired at i = 4. (end=" " replaces the newline that print normally adds with a space.)

while also has an else that runs when the condition becomes false normally:

i = 0
while i < 3:
    i += 1
else:
    print("else", i)

Output: else 3. And for i in range(2, 10, 3) visits 2, 5, 8.

Simultaneous assignment. In a, b = b, a + b the whole right side is evaluated first, using the old values, and only then are both names bound:

a, b = 0, 1
for _ in range(5):
    a, b = b, a + b
print(a, b)

Output: 5 8. In the same way, x, y = y, x swaps two variables.

How to trace a loop program exactly

  1. Write a table with one column for every variable that changes, and one row per iteration.

  2. Evaluate the loop condition before each iteration; record the variable values at the end of each iteration.

  3. Note where print uses end=, sep= or several arguments, so you know where spaces and newlines go.

  4. On break stop immediately (and skip a loop else); on continue jump to the next iteration without running the rest of the body.

  5. Write the output exactly, with a space between printed arguments unless sep= says otherwise.

Functions, arguments and scope

Arguments can be passed by position or by keyword. A parameter with a default may be omitted. Parameters after a bare * are keyword-only. A function without return returns None:

def g2(a, b=2, *, c=3):
    return (a, b, c)

print(g2(1), g2(1, c=5), g2(b=7, a=0))

Output: (1, 2, 3) (1, 2, 5) (0, 7, 3).

*args collects extra positional arguments into a tuple, and **kw collects extra keyword arguments into a dict. In a call, * unpacks an iterable into positional arguments and ** unpacks a dict into keyword arguments:

def h(a, *args, **kw):
    return a, args, kw

print(h(1, 2, 3, x=4))
print(h(*[5, 6], **{"y": 7}))

Output:

(1, (2, 3), {'x': 4})
(5, (6,), {'y': 7})

The mutable-default trap. Default values are evaluated once, when the def statement runs, not on each call. A mutable default is therefore shared by all calls that omit it:

def f(x, l=[]):
    l.append(x)
    return l

print(f(1), f(2), f(3, [9]), f(4))

Output: [1, 2, 4] [1, 2, 4] [9, 3] [1, 2, 4]. The three calls that omit l all return the same list object, which ends as [1, 2, 4] before print runs. f(3, [9]) uses a fresh list passed in, so it is unaffected.

Scope (LEGB). A name is looked up in the Local scope, then any Enclosing function, then Global, then Built-in. Assigning to a name inside a function makes it local to that function unless declared global or nonlocal. Reading a global needs no declaration. global x rebinds the module-level name; nonlocal x rebinds the name in the nearest enclosing function:

x = 10
def p():
    x = 5
    def q():
        nonlocal x
        x += 1
        return x
    return q()
print(p(), x)

Output: 6 10. q changes p's x (5 to 6); the global x stays 10.

Closures. An inner function keeps access to the enclosing variables it uses, and it sees their current value when it is called, not the value when it was defined:

def counter():
    c = 0
    def inc():
        nonlocal c
        c += 1
        return c
    return inc

k = counter()
print(k(), k(), k())

Output: 1 2 3. The late-binding effect:

def mk():
    fs = []
    for i in range(3):
        fs.append(lambda: i)
    return [f() for f in fs]
print(mk())

Output: [2, 2, 2], because all three lambdas read the same i, which is 2 after the loop ends. Writing fs.append(lambda i=i: i) instead stores the current value as a default (defaults are evaluated when the lambda is created), and the output becomes [0, 1, 2].

WORKED EXAMPLE

What does this program print?

x = 3
def u():
    global x
    x = x * 2
    return x
print(u() + u(), x)
Solution
  1. The expression u() + u() is evaluated left to right, and both arguments of print are evaluated before anything is printed.

  2. First u(): x becomes 3 * 2 = 6, returns 6.

  3. Second u(): x becomes 6 * 2 = 12, returns 12.

  4. The sum is 6 + 12 = 18.

  5. The second argument x is read after both calls, so it is 12.

Answer: 18 12

EXAM TIP

If a function assigns to a name anywhere in its body, that name is local for the whole function. Reading it before the assignment (without global/nonlocal) raises an UnboundLocalError. lst.append(v) inside a function mutates a global list without needing global, because it does not rebind the name, but lst += [v] inside the same function is an assignment to lst and raises UnboundLocalError unless lst is declared global. A comprehension has its own scope, so its loop variable does not exist after it; a for loop's variable keeps its last value after the loop (after for j in range(3): pass, j is 2).

Built-in functions, generators and classes

lambda args: expr is a one-expression function. enumerate(it, start) pairs each item with a counter; zip pairs items and stops at the shortest input; map and filter are lazy, so wrap them in list(...) to see the values. sorted(it, key=f, reverse=True) sorts by f(item) and is stable (items with equal keys keep their original order). min and max accept a key and return the first of equally ranked items. sum(it, start) adds from start. any is true if some item is true; all is true if every item is true.

print(list(enumerate("ab", 1)), list(zip([1, 2, 3], "ab")))
print(list(map(lambda v: v * v, [1, 2, 3])), list(filter(lambda v: v % 2, range(6))))
print(sorted(["bb", "a", "ccc", "dd"], key=len), sorted([3, 1, 2], reverse=True))
print(max(["apple", "fig", "kiwi"], key=len), sum([1, 2, 3], 10), any([0, "", 3]), all([1, []]))

Output:

[(1, 'a'), (2, 'b')] [(1, 'a'), (2, 'b')]
[1, 4, 9] [1, 3, 5]
['a', 'bb', 'dd', 'ccc'] [3, 2, 1]
apple 16 True False

'bb' stays before 'dd' because both have length 2 and the sort is stable.

Generators. A function containing yield returns a generator: each next() runs the body up to the next yield and hands back that value. A generator can be consumed only once:

def gen(n):
    for i in range(n):
        yield i * i

gg = gen(3)
print(next(gg), list(gg), list(gg))

Output: 0 [1, 4] []. next took 0, the first list took the rest, and the second list found the generator exhausted.

Classes. self.name is first looked up on the instance, then on the class. A class attribute is shared by all instances. Mutating it through self (self.items.append(v)) changes the shared object, but assigning through self (self.count += 1) creates a separate instance attribute and leaves the class attribute alone:

class C:
    items = []
    count = 0
    def __init__(self, v):
        self.v = v
        self.items.append(v)
        self.count += 1

p = C(1)
q = C(2)
print(C.items, p.items is q.items, C.count, p.count, q.count)

Output: [1, 2] True 0 1 1.

Recursion and exact-output tracing

A recursive function needs a base case that returns without recursing, and a recursive case that moves toward it. Each call gets its own local variables. Statements placed before the recursive call run on the way down; statements placed after it run on the way back up, in reverse order of the calls.

Pre-order versus post-order printing:

def r(n):
    if n <= 0:
        return 0
    print(n, end=" ")
    return n + r(n - 2)
print(r(7))

def h2(n):
    if n == 0:
        return
    h2(n - 1)
    print(n, end=" ")
h2(4)
print()

Output:

7 5 3 1 16
1 2 3 4 

For r(7): it prints 7, 5, 3, 1, then r(-1) returns 0, and the return values add up as 7 + 5 + 3 + 1 + 0 = 16. That sum is printed after the numbers, on the same line, because each of them ended with a space instead of a newline. In h2, the print comes after the recursive call, so the numbers appear in increasing order.

For a function with two recursive calls, such as

def fib(n):
    return n if n < 2 else fib(n - 1) + fib(n - 2)
print(fib(6))

build a table of values from the base cases up: fib(0)=0, fib(1)=1, fib(2)=1, fib(3)=2, fib(4)=3, fib(5)=5, fib(6)=8. The output is 8. Working bottom-up is faster and safer than expanding the whole call tree.

NUMBER OF CALLS MADE BY NAIVE FIBONACCI RECURSION

For the fib above, which returns directly for n < 2 and otherwise calls itself on n-1 and n-2, with F(0)=0, F(1)=1. C(n) counts every call, the first one included; for example fib(6) makes C(6) = 2·13 − 1 = 25 calls.

WORKED EXAMPLE

What does this program print?

def g(a, b=[]):
    b.append(a)
    return len(b)
print(g(1), g(2), g(3))
s = "abcdef"
print(s[1::2], s[-2:], s[:-1][::-1])
Solution
  1. g(1): the default list is created once and is empty; after append(1) its length is 1.

  2. g(2): the same default list is reused, now [1, 2], so the length is 2.

  3. g(3): the list is [1, 2, 3], so the length is 3. The first line is 1 2 3.

  4. s[1::2] takes indices 1, 3, 5, giving bdf.

  5. s[-2:] takes the last two characters, ef.

  6. s[:-1] is abcde; reversing it with [::-1] gives edcba. The second line is bdf ef edcba.

Answer: 1 2 3 on the first line and bdf ef edcba on the second.

EXAM TIP

When a trace goes wrong it is almost always one of these: using / where the program has //; forgetting that the remainder takes the divisor's sign; treating int() as floor; treating a copy as an alias (or the reverse); the shared mutable default; an else on a loop that ended with break; a generator read twice; or printing a recursion's output in the wrong order. Check each one before you choose an option.

PREVIOUS-YEAR QUESTIONS

10 questions from the DA papers

Try each question first, then open the answer. We placed each question under a topic ourselves; the exam paper does not label topics.

See these papers in full: GATE DA 2026 · GATE DA 2025 · GATE DA 2024

GATE 2026 DA Q.16

GATE 2026 · DAQ.16 · 1 mark · MCQ

Consider the given Python program.

def append_to_lst(val, lst=[]):
      lst.append(val)
      return lst
print(append_to_lst(1))
print(append_to_lst(2))
print(append_to_lst(3, []))

Which of the following is the correct output of this program?

  1. (A)

    [1]
    [2]
    [3]

  2. (B)

    [1]
    [1, 2]
    [3]

  3. (C)

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

  4. (D)

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

Answer and solution
See the question in the paper
GATE 2026 DA Q.16: answer and solution

GATE 2026 DA Q.39

GATE 2026 · DAQ.39 · 2 marks · MCQ

A recursive function in Python is given.

def mystery(n):
    if n <= 0:
        return 1
    else:
        return mystery(n-1) + mystery(n-2)

Now, consider the following function call:

mystery(4)

Assume that a typical runtime stack is used to manage function calls. Each function call is pushed onto the stack and removed only after it finishes execution.

Which of the following options denotes the total number of function calls (i.e., the total number of stack activations), including the initial call, to compute mystery(4)?

  1. (A)

    5

  2. (B)

    9

  3. (C)

    15

  4. (D)

    17

Answer and solution
See the question in the paper
GATE 2026 DA Q.39: answer and solution

GATE 2026 DA Q.50

GATE 2026 · DAQ.50 · 2 marks · MSQ

Consider the given Python program.

def outer():
    x = []
    def inner(val):
        x.append(val)
        return x
    return inner
f1 = outer()
f2 = outer()
print(f1(10))   # Line P
print(f1(20))   # Line Q
print(f2(30))   # Line R
print(f1(40))   # Line S

Which of the following options is/are correct?

  1. (A)

    f1 and f2 share the same list x

  2. (B)

    Output of Line Q is [10, 20]

  3. (C)

    Output of Line R is [10, 20, 30]

  4. (D)

    Output of Line S is [10, 20, 40]

Answer and solution
See the question in the paper
GATE 2026 DA Q.50: answer and solution

GATE 2026 DA Q.58

GATE 2026 · DAQ.58 · 2 marks · NAT

Consider the given Python program.

def fun(L, i=0):
      if i >= len(L)-1:
            return 0
      if L[i] > L[i+1]:
            L[i+1], L[i] = L[i], L[i+1]
            return 1+fun(L, i+1)
      else:
            return fun(L, i+1)
data = [5, 3, 4, 1, 2]
count = 0
for _ in range(len(data)):
      count += fun(data)
print(count)

The output of the program is ________ . (Answer in integer)

Answer and solution
See the question in the paper
GATE 2026 DA Q.58: answer and solution

GATE 2025 DA Q.47

GATE 2025 · DAQ.47 · 2 marks · MCQ

Consider the following Python code snippet.

A={"this","that"}
B={"that","other"}
C={"other","this"}
while "other" in C:
    if "this" in A:
      A,B,C=A-B,B-C,C-A
    if "that" in B:
      A,B,C=C|A,A|B,B|C

When the above program is executed, at the end, which of the following sets contains "this"?

  1. (A)

    Only A

  2. (B)

    Only B

  3. (C)

    Only C

  4. (D)

    A, C

Answer and solution
See the question in the paper
GATE 2025 DA Q.47: answer and solution

GATE 2024 DA Q.38

GATE 2024 · DAQ.38 · 2 marks · MCQ

Consider the following Python code:

def count(child_dict, i):
    if i not in child_dict.keys():
        return 1
    ans = 1
    for j in child_dict[i]:
        ans += count(child_dict, j)
    return ans

child_dict = dict()
child_dict[0] = [1,2]
child_dict[1] = [3,4,5]
child_dict[2] = [6,7,8]
print(count(child_dict,0))

Which ONE of the following is the output of this code?

  1. (A)

    6

  2. (B)

    1

  3. (C)

    8

  4. (D)

    9

Answer and solution
See the question in the paper
GATE 2024 DA Q.38: answer and solution

GATE 2024 DA Q.39

GATE 2024 · DAQ.39 · 2 marks · MCQ

Consider the function computeS(X) whose pseudocode is given below:

computeS(X)
S[1] ← 1
for i ← 2 to length(X)
   S[i] ← 1
   if X[i-1] ≤ X[i]
         S[i] ← S[i] + S[i-1]
   end if
end for
return S

Which ONE of the following values is returned by the function computeS(X) for X = [6, 3, 5, 4, 10]?

  1. (A)

    [1, 1, 2, 3, 4]

  2. (B)

    [1, 1, 2, 3, 3]

  3. (C)

    [1, 1, 2, 1, 2]

  4. (D)

    [1, 1, 2, 1, 5]

Answer and solution
See the question in the paper
GATE 2024 DA Q.39: answer and solution

GATE 2024 DA Q.41

GATE 2024 · DAQ.41 · 2 marks · MCQ

Consider the following Python function:

def fun(D, s1, s2):
        if s1 < s2:
            D[s1], D[s2] = D[s2], D[s1]
            fun(D, s1+1, s2-1)

What does this Python function fun() do? Select the ONE appropriate option below.

  1. (A)

    It finds the smallest element in D from index s1 to s2, both inclusive.

  2. (B)

    It performs a merge sort in-place on this list D between indices s1 and s2, both inclusive.

  3. (C)

    It reverses the list D between indices s1 and s2, both inclusive.

  4. (D)

    It swaps the elements in D at indices s1 and s2, and leaves the remaining elements unchanged.

Answer and solution
See the question in the paper
GATE 2024 DA Q.41: answer and solution

PRACTICE

6 questions to test yourself

PRACTICE 11 mark · MCQ

What does the following program print?

a = [1, 2, 3]
b = a
c = a + [4]
b += [5]
print(a, c)
  1. (A)

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

  2. (B)

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

  3. (C)

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

  4. (D)

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

Answer and solution

Answer: (B)

  1. b = a makes b another name for the same list object.

  2. c = a + [4] builds a NEW list [1, 2, 3, 4]; it is computed before b changes and is never touched again.

  3. b += [5] on a list extends the object in place, so a (the same object) becomes [1, 2, 3, 5].

  4. The output is [1, 2, 3, 5] [1, 2, 3, 4], option B.

PRACTICE 21 mark · NAT

What is the value printed by the following statement? (Python 3)

print((-17 // 5) * (17 % -5))
Answer and solution

Answer:

  1. -17 // 5 is the floor of -3.4, which is -4.

  2. 17 % -5: the remainder takes the sign of the divisor and satisfies 17 = (-5)(-4) + r, so r = 17 - 20 = -3.

  3. The product is (-4) * (-3) = 12.

PRACTICE 31 mark · NAT

What is the value printed by the following statement? (Python 3)

print(int(-7 / 2) - (-7 // 2) + round(2.5))
Answer and solution

Answer:

  1. -7 / 2 is -3.5, and int truncates toward zero, giving -3.

  2. -7 // 2 is the floor of -3.5, which is -4.

  3. round(2.5) rounds the exact half to the even neighbour, 2.

  4. The value is -3 - (-4) + 2 = 3.

PRACTICE 42 marks · NAT

What does the following program print?

def f(n):
    if n < 2:
        return n
    return f(n - 1) + 2 * f(n - 2)
print(f(6))
Answer and solution

Answer:

  1. Base cases: f(0) = 0, f(1) = 1.

  2. f(2) = f(1) + 2 f(0) = 1.

  3. f(3) = f(2) + 2 f(1) = 1 + 2 = 3.

  4. f(4) = f(3) + 2 f(2) = 3 + 2 = 5.

  5. f(5) = f(4) + 2 f(3) = 5 + 6 = 11.

  6. f(6) = f(5) + 2 f(4) = 11 + 10 = 21.

PRACTICE 52 marks · MCQ

What does the following program print?

def p(x, acc=[]):
    acc.append(x)
    return acc

def q(x, acc=[]):
    acc = acc + [x]
    return acc

print(p(1), p(2), q(1), q(2), len(p(3)))
  1. (A)

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

  2. (B)

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

  3. (C)

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

  4. (D)

    [1] [2] [1] [2] 1

Answer and solution

Answer: (B)

  1. p mutates its default list, which is created once. p(1), p(2) and p(3) all return that same object; after the three calls it is [1, 2, 3].

  2. print evaluates all its arguments first and prints afterwards, so the first two arguments both show the final state [1, 2, 3].

  3. q does acc = acc + [x], which builds a new list and rebinds the local name; the shared default stays []. So q(1) is [1] and q(2) is [2].

  4. len(p(3)) is 3, the length of the shared list at that moment.

  5. The output is [1, 2, 3] [1, 2, 3] [1] [2] 3, option B.

PRACTICE 62 marks · MSQ

Let A = {1, 2, 3, 4, 5}, B = {4, 5, 6} and C = {2, 5, 7} be Python sets. Which of the following expressions evaluate to True?

  1. (A)

    (A & B) | C == {2, 4, 5, 7}

  2. (B)

    (A - B) ^ C == {1, 3, 5, 7}

  3. (C)

    A - (B | C) == {1, 3, 4}

  4. (D)

    len(A ^ B) == 5

Answer and solution

Answer: (A), (B)

  1. A: A & B = {4, 5}; its union with C is {2, 4, 5, 7}. Since &, |, ^ and - all bind tighter than ==, the comparison is evaluated last and is True.

  2. B: A - B = {1, 2, 3}; symmetric difference with C = {2, 5, 7} removes the shared 2 and keeps the rest: {1, 3, 5, 7}. True.

  3. C: B | C = {2, 4, 5, 6, 7}; A minus it is {1, 3}, not {1, 3, 4}. False.

  4. D: A ^ B = {1, 2, 3, 6} has length 4 (check: |A| + |B| − 2|A ∩ B| = 5 + 3 − 4 = 4), not 5. False.

  5. So A and B are correct.

OFFICIAL GATE 2027 SYLLABUS WORDING

Copied from the GATE 2027 syllabus; see all 2027 syllabi.

GATE DA

Programming in Python

Preparing in Kolkata? IAE Academy's course for GATE DA.