Level 2 — RecallPython & Scientific Computing

Python & Scientific Computing

30 minutes40 marksprintable — key stays hidden on paper

Level 2 — Recall & Standard Problems

Time limit: 30 minutes Total marks: 40

Answer all questions. Show working where computation is required. Use code formatting mentally for any code you write.


Q1. (3 marks) State the output type produced by each expression, and give the value: (a) 3 / 2 (b) 3 // 2 (c) type([]) is list

Q2. (4 marks) Write a Python function factorial(n) using a loop (not recursion) that returns n!n! for a non-negative integer n. Include one line that handles the case n == 0.

Q3. (4 marks) Rewrite the following loop as a single list comprehension, then as a generator expression. Explain the key memory difference between the two.

squares = []
for x in range(10):
    if x % 2 == 0:
        squares.append(x*x)

Q4. (5 marks) Given a = np.array([1, 2, 3, 4]), write the vectorized NumPy expression (no Python loops) for each: (a) elementwise square, (b) the mean, (c) a boolean mask of elements > 2, (d) the sum of only elements > 2.

Q5. (5 marks) Explain NumPy broadcasting. State the two broadcasting rules and give the resulting shape when arrays of shapes (3, 1) and (1, 4) are added together.

Q6. (5 marks) Given a Pandas DataFrame df with columns ['name', 'age', 'city']: (a) select the age column as a Series, (b) filter rows where age >= 18, (c) compute the mean age grouped by city.

Q7. (4 marks) Name the appropriate pandas function to load each file format, and state one distinctive property of each format: (a) .csv (b) .json (c) .parquet

Q8. (4 marks) Match each Git command to its purpose: git clone, git add, git commit, git push. Then state the difference between the staging area and the working directory.

Q9. (3 marks) A tool installs a per-project isolated set of Python packages. (a) Name one command to create a virtual environment with the built-in venv module. (b) State one reason virtual environments are used.

Q10. (3 marks) You call np.zeros((3,4)) but get a TypeError. Describe the systematic debugging steps you would take, including which two objects you would inspect first.


End of paper

Answer keyMark scheme & solutions

Q1. (3 marks — 1 each) (a) float, value 1.5 — true division always yields float. (b) int, value 1 — floor division truncates toward negative infinity. (c) bool, value Truetype([]) is exactly the list class object.

Q2. (4 marks)

def factorial(n):
    result = 1                # handles n == 0 → 0! = 1
    for i in range(2, n+1):
        result *= i
    return result

Marks: correct signature/return (1), loop over range (1), accumulator init to 1 (1), n==0 gives 1 correctly (1). The empty range for n=0,1 leaves result=1, which is why no explicit branch is strictly needed.

Q3. (4 marks) List comprehension (1): squares = [x*x for x in range(10) if x % 2 == 0] Generator (1): squares = (x*x for x in range(10) if x % 2 == 0) Memory difference (2): the list comprehension builds and stores the full list in memory eagerly; the generator produces values lazily one at a time on iteration, using O(1) memory rather than O(n).

Q4. (5 marks) (a) a**2[1,4,9,16] (1) (b) a.mean()2.5 (1) (c) a > 2[False, False, True, True] (1) (d) a[a > 2].sum()7 (2: masking 1 + sum 1). Also accept a[a>2].sum() = 3+4 = 7.

Q5. (5 marks) Broadcasting (1): a mechanism to perform elementwise operations on arrays of different shapes without copying data, by virtually stretching dimensions. Rules (2): (i) Align shapes from the trailing (rightmost) dimension; prepend 1s to the shorter shape. (ii) Two dimensions are compatible if they are equal or one of them is 1; a size-1 dimension is stretched to match. Result shape (2): (3,1) + (1,4)(3,4).

Q6. (5 marks) (a) df['age'] (1) — returns a Series. (b) df[df['age'] >= 18] (2) — boolean indexing. (c) df.groupby('city')['age'].mean() (2).

Q7. (4 marks — 1 each pair, 2 for a & b, adjust) (a) pd.read_csv — plain text, human-readable, no type/schema info stored. (b) pd.read_json — nested/hierarchical structure, text-based. (c) pd.read_parquet — columnar, compressed, binary; preserves dtypes; efficient for large data. Marks: correct function names (2), one property each ≈ (2).

Q8. (4 marks) git clone = copy a remote repository locally (0.5); git add = stage changes (0.5); git commit = record staged snapshot to history (0.5); git push = upload local commits to remote (0.5). Difference (2): the working directory holds your actual editable files; the staging area (index) holds the set of changes you have marked to be included in the next commit.

Q9. (3 marks) (a) python -m venv myenv (2). (b) Any one (1): isolates project dependencies / avoids version conflicts between projects / makes environments reproducible.

Q10. (3 marks) Steps (any 3 of): read the full traceback bottom line and the error message (1); inspect the argument passed and its type — here confirm (3,4) is a tuple, not e.g. two separate ints or a string (1); check np is imported and refers to numpy (1); consult np.zeros documentation / help(np.zeros) for the expected signature (1). First two objects to inspect: the offending argument and the function/object being called.

[
  {"claim": "3//2 == 1 and 3/2 == 1.5", "code": "result = (3//2 == 1) and (3/2 == 1.5)"},
  {"claim": "factorial loop gives 5! = 120", "code": "r=1\nfor i in range(2,6): r*=i\nresult = (r == 120)"},
  {"claim": "sum of numpy elements >2 in [1,2,3,4] is 7", "code": "import numpy as np\na=np.array([1,2,3,4])\nresult = (int(a[a>2].sum()) == 7)"},
  {"claim": "mean of [1,2,3,4] is 2.5", "code": "import numpy as np\nresult = (float(np.array([1,2,3,4]).mean()) == 2.5)"},
  {"claim": "broadcasting (3,1)+(1,4) yields shape (3,4)", "code": "import numpy as np\nx=np.ones((3,1))+np.ones((1,4))\nresult = (x.shape == (3,4))"}
]