Follow Us
Select Medium / माध्यम चुनें:
Eng (English) Beng (বাংলা) Hindi (हिन्दी)
WBB • Class XII • Computer Science • Ch 1
Estimated Time: 120 Mins
Study Progress: In Progress

Programming in Python

Welcome to the comprehensive, curriculum-aligned master study guide for Chapter 1: Programming in Python, prescribed under the official West Bengal Council of Higher Secondary Education (WBCHSE) Class 12 Computer Science syllabus. Python is a premier high-level, dynamically typed, interpreted, and multi-paradigm programming language renowned for its clean syntax, rapid prototyping capabilities, and extensive standard library ecosystem. This chapter bridges the algorithmic foundations introduced in Class 11 with advanced software development paradigms. Students will dissect the internal CPython execution pipeline—transitioning from human-readable source code (.py) through Abstract Syntax Trees (AST) and optimized bytecode (.pyc) to real-time interpretation on the stack-based Python Virtual Machine (PVM). The curriculum provides exhaustive mastery over Python's memory model, reference counting, object mutability, and identity mechanisms. Learners will master sequence containers including Strings, Lists, and Tuples, explore hash-based Mappings and Sets, construct sophisticated comprehension expressions, and design modular architectures utilizing first-class functions, the LEGB scope hierarchy, persistent file stream I/O, and robust exception-handling protocols required for WBCHSE board examinations and modern computational engineering.

Why This Chapter Matters

Python has emerged as the universal lingua franca across modern computational sciences, software engineering, artificial intelligence, data science, and cloud computing. For Class 12 Computer Science students under WBCHSE, mastering Python is not merely an academic milestone for board examinations, but a gateway to foundational software design and algorithmic fluency. Understanding how CPython manages memory through reference counting and garbage collection enables developers to write high-performance, leak-free applications. Distinguishing between mutable and immutable data structures prevents catastrophic runtime side-effects in enterprise databases and multi-threaded systems. Furthermore, fluency in structured exception handling and persistent file operations equips students to build production-grade software that interfaces securely with external storage systems, APIs, and real-world datasets. This chapter establishes the core programming rigor that underpins competitive examinations, university degree programs in computer engineering, and global technology careers.

Chapter Roadmap & Progression

1 1. Python Genesis, Architecture & C...
2 2. Memory Architecture, Mutability...
3 3. Structured Control Flow, Iterati...
4 4. Sequence Containers in Depth: St...
5 5. Hashable Collections: Dictionari...
6 6. Modular Functions, LEGB Scope, P...

Complete Concept Guide (100% Curriculum Coverage)

1. Python Genesis, Architecture & CPython Execution Pipeline

1.1 The Genesis, Features & Execution Pipeline of Python

Python was conceived in the late 1980s by Guido van Rossum at the Centrum Wiskunde & Informatica (CWI) in the Netherlands as a successor to the ABC programming language. Officially released in February 1991, Python was architected around readability, explicit syntax (as articulated in Tim Peters' The Zen of Python, PEP 20), and dynamic multi-paradigm flexibility supporting procedural, object-oriented, and functional programming methodologies.

Core Paradigm Characteristics of Python:
  • Interpreted & Hybrid Execution: Unlike pure compiled languages (such as C/C++) that produce native machine binaries, or pure interpreters that interpret source lines on the fly, standard Python (CPython) compiles source code into an intermediate, optimized format known as bytecode before executing it on a runtime virtual machine.
  • Dynamically Typed: Variable types are not declared explicitly by the programmer; instead, data types are bound dynamically to runtime objects rather than variable names.
  • Automatic Memory Management: CPython integrates reference counting coupled with a generational cyclic garbage collector to track object lifetimes and reclaim orphaned heap memory automatically.
  • Batteries Included Standard Library: Comprehensive built-in support for mathematical operations, file I/O, regular expressions, networking, serialization, and cryptographic hashing without third-party dependencies.
1.2 Deep-Dive into the CPython Execution Architecture

The execution of a Python script follows a rigorous, multi-tiered compilation and runtime pipeline:

Pipeline Stage Component / Process Artifact & Architectural Function
1. Lexical Analysis Tokenizer & Scanner Converts raw UTF-8 source characters into discrete language tokens (keywords, identifiers, literals, operators, punctuation, and indentation tokens INDENT / DEDENT).
2. Syntactic Parsing Parser & Grammar Engine Validates language syntax against Python's PEG grammar and generates an in-memory Abstract Syntax Tree (AST). Syntax errors are raised at this phase prior to execution.
3. Bytecode Compilation CPython Code Generator Compiles the AST into platform-independent intermediate instructions known as bytecode. These instructions are cached as .pyc files in the pycache directory with magic version headers.
4. Virtual Machine Runtime Python Virtual Machine (PVM) A stack-based interpreter loop (ceval.c in CPython) that consumes bytecode instructions sequentially, manages execution frames, and executes low-level CPU machine calls.
1.3 Lexical Elements, PEP 8 Standards & Execution Modes

Python eliminates traditional code block delimiters such as curly braces {} or begin...end keywords found in C or Pascal. Instead, Python employs Syntactic Indentation:

  • Whitespace & Indentation (PEP 8): A block of code is delineated strictly by consistent leading whitespace. PEP 8 mandates exactly 4 spaces per indentation level. Tabs and spaces must never be mixed (enforced via TabError in Python 3).
  • Identifiers & Naming Conventions: Identifiers must commence with an alphabet ([a-zA-Z]) or an underscore (_), followed by alphanumeric characters or underscores. They are strictly case-sensitive (e.g., totalScore and TotalScore are separate identifiers). Reserved keywords (e.g., def, class, if, lambda, yield, async) cannot serve as identifiers.
  • Comments & Docstrings: Single-line comments commence with # and are discarded during lexical analysis. Multi-line documentation strings (docstrings) are defined using triple-quoted string literals ("""...""" or '''...''') placed immediately below function, class, or module headers, accessible at runtime via the .doc attribute.
  • Interactive Mode (REPL) vs. Script Mode: In Interactive Mode, Python executes a Read-Eval-Print Loop (REPL), ideal for immediate expression evaluation and debugging. In Script Mode, complete source files (.py) are executed from start to finish via command-line invocations: python script.py.

2. Memory Architecture, Mutability Matrix & Operator Mechanics

2.1 Variables as Object References & Python's Unified Memory Model

In languages like C or C++, a variable represents a named, statically typed memory bucket that directly houses raw binary data. In Python, everything is an object. A variable is simply a symbolic reference (tag or pointer) bound to an object residing on the heap:

# Variable Binding and Object Reference Illustration
x = 256
y = x
print(id(x), id(y))  # Identical memory addresses
print(x is y)        # True: Identity equality

x = x + 1            # Creates a NEW integer object 257; rebinds x
print(id(x) == id(y))# False: x now references a different heap object
print(y)             # 256: y continues referencing original object
2.2 The Fundamental Mutability vs. Immutability Taxonomy

Every Python object possesses three intrinsic properties:

  • Identity: The memory address where the object resides, retrievable via id(obj).
  • Type: The class describing the object's structure and supported operations, retrievable via type(obj).
  • Value: The data payload contained within the object.
Classification Built-in Types State Modification Behavior Hashability & Key Usage
Immutable int, float, complex, bool, str, tuple, frozenset, bytes Value cannot be changed after creation. Any modification operation (e.g., string concatenation s += 'a') instantiates a totally new object with a new id(). Hashable (if elements are hashable). Can safely serve as dictionary keys and set elements.
Mutable list, dict, set, bytearray Can be altered in-place (e.g., lst.append(5), d['k'] = 'v') without changing the object's identity (memory address id() remains constant). Unhashable. Cannot be used as dictionary keys or set elements (raises TypeError: unhashable type).
2.3 Comprehensive Operators & Precedence Mechanics

Python provides a comprehensive set of operators categorized by their operational characteristics:

  • Arithmetic Operators: Addition (+), Subtraction (-), Multiplication (*), True Division (/ produces a float, e.g., 7 / 2 = 3.5), Floor Division (// produces mathematical floor: 7 // 2 = 3, -7 // 2 = -4), Modulus (% remainder), Exponentiation ( right-associative: 2 3 2 = 2 9 = 512).
  • Relational & Chained Comparisons: ==, !=, >, <, >=, <=. Python uniquely supports chained comparisons: 10 < x <= 50 evaluates identically to (10 < x) and (x <= 50) with x evaluated only once.
  • Logical Operators with Short-Circuit Evaluation:
    • and: Returns the first falsey operand, or the last truthy operand if all are truthy (e.g., 0 and 5 yields 0; 3 and 7 yields 7).
    • or: Returns the first truthy operand, or the last operand if all are falsey (e.g., 5 or 10 yields 5; [] or 'apple' yields 'apple').
    • not: Unary boolean negation (not 0 yields True).
  • Identity (is, is not) vs. Value Equality (==, !=): a == b invokes the rich comparison method a.eq(b) to evaluate structural value equality. In contrast, a is b evaluates pointer identity equality: id(a) == id(b).
  • Membership Operators: in and not in test containment within sequences (strings, lists, tuples) in $O(N)$ time or within hash-tables (sets, dict keys) in average $O(1)$ time.
  • Bitwise Operators: Binary AND (&), OR (|), XOR (^), NOT (~), Left Shift (<<), Right Shift (>>) operating on two's complement integer representations.

3. Structured Control Flow, Iteration Calculus & Loop-Else Logic

3.1 Conditional Branching Architecture: if, elif, and else

Conditional statements govern the selective execution of code blocks based on truth value evaluation. In Python, an expression is considered falsey if it is None, False, numeric zero (0, 0.0, 0j), or an empty collection ("", [], (), {}, set()). All other objects evaluate to truthy.

# Multi-Branch Decision Tree & Ternary Operator
marks = 85

# Traditional if-elif-else cascade
if marks >= 90:
    grade = 'AA'
elif marks >= 80:
    grade = 'A+'
elif marks >= 70:
    grade = 'A'
else:
    grade = 'Pass'

# Conditional Ternary Expression: [value_if_true] if [condition] else [value_if_false]
status = "Honors" if marks >= 80 else "Regular"
3.2 Iteration Architecture: while Loops, for Loops & range() Calculus

Python provides two primary looping constructs tailored for condition-controlled and sequence-controlled iteration:

  • The while Loop: Repeats execution of a code block indefinitely as long as a boolean predicate remains True. Requires explicit state initialization and loop-variable modification within the loop body to avoid infinite iteration traps.
  • The for Loop & Iterator Protocol: A for loop in Python operates as a generic iterator-consumer. Under the hood, it invokes iter(iterable) to acquire an iterator object and repeatedly calls next() until a StopIteration exception is raised.
  • The range(start, stop, step) Object: Generates an immutable, space-efficient arithmetic sequence. It computes values on-demand in $O(1)$ memory regardless of size:
    • range(10): Generates integers 0 through 9 (inclusive of start 0, exclusive of stop 10).
    • range(2, 10, 2): Generates 2, 4, 6, 8.
    • range(10, 0, -2): Generates descending sequence 10, 8, 6, 4, 2.
3.3 Jump Statements & The Python-Specific Loop-Else Construct

Loop execution flow can be controlled dynamically using three jump keywords:

  • break: Immediately terminates the innermost loop, jumping control to the statement following the loop body.
  • continue: Immediately abandons the remainder of the current iteration, jumping control directly to the condition re-evaluation (in while) or the next item fetch (in for).
  • pass: A syntactical no-op statement. Used as a placeholder in empty functions, loops, or exception blocks where a statement is grammatically required.
  • The else Clause in Loops (Unique to Python): The else block attached to a for or while loop executes if and only if the loop completes its entire iteration cycle naturally without encountering a break statement:
# Prime Number Search Demonstrating for-else Mechanics
num = 29
for divisor in range(2, int(num ** 0.5) + 1):
    if num % divisor == 0:
        print(f"{num} is composite (divisible by {divisor}).")
        break
else:
    # Executes ONLY if no divisor triggered the 'break'
    print(f"{num} is a prime number!")
Statement / Keyword Primary Function & Behavior Impact on Loop Execution Flow Triggers Loop else Block?
break Aborts loop execution unconditionally. Terminates the innermost enclosing loop immediately; jumps to statements outside the loop. No (suppresses loop else block)
continue Skips remainder of current iteration cycle. Discards following lines in loop body; immediately moves to next iteration test or sequence item. Yes (if loop completes naturally)
pass Syntactic null placeholder (no operation). Executes nothing; control continues sequentially to the very next line within the block. Yes (does not disrupt loop completion)

4. Sequence Containers in Depth: Strings, Lists & Tuples

4.1 Sequence Indexing Calculus & Slicing Mechanics

Python provides unified sequence operations across Strings (str), Lists (list), and Tuples (tuple). Sequences support bidirectional zero-based indexing:

  • Positive Forward Indexing: Begins at index 0 for the first element, up to n - 1 for an $n$-element sequence.
  • Negative Reverse Indexing: Begins at index -1 for the final element, down to -n for the initial element.
  • Slicing Calculus seq[start:stop:step]: Extracts a contiguous or strided sub-sequence starting at index start (inclusive), terminating strictly before index stop (exclusive), advancing by increments of step:
    • If step > 0: Default start = 0, default stop = len(seq).
    • If step < 0: Default start = -1, default stop = -len(seq) - 1. Stride seq[::-1] produces an exact inverted copy.
    • Slices never raise IndexError when boundaries exceed sequence length; Python clamps bounds gracefully.
4.2 Strings (str): Immutability, Formatting & Essential Methods

Strings are immutable sequences of Unicode code points. Key standard methods include:

  • Case Transformations: .upper(), .lower(), .title(), .capitalize(), .swapcase().
  • Sanitization & Trimming: .strip([chars]), .lstrip(), .rstrip() remove whitespace or specified characters.
  • Search & Verification: .find(sub) (returns -1 if not found), .index(sub) (raises ValueError if not found), .count(sub), .startswith(prefix), .endswith(suffix).
  • Splitting & Joining: .split(sep) decomposes a string into a list of substrings; sep.join(iterable) joins string elements into a single delimited string.
  • Interpolation (f-strings, Python 3.6+): Formatted string literals evaluate embedded expressions at runtime: f"Student {name}: Score = {score:.2f}".
4.3 Lists (list): Dynamic Arrays, Comprehensions & Copy Semantics

Lists are mutable, dynamically sized arrays storing heterogeneous object references.

Category Syntax / Method Operational Mechanism & Complexity
Insertion lst.append(x)
lst.extend(iterable)
lst.insert(idx, x)
append adds single element at end in amortized $O(1)$. extend appends all elements from an iterable. insert shifts elements rightward in $O(N)$.
Deletion lst.pop([idx])
lst.remove(x)
del lst[idx]
pop() removes and returns element (default last in $O(1)$; at index in $O(N)$). remove(x) finds and deletes first occurrence of value x or raises ValueError.
Comprehensions [expr for x in seq if cond] Concise, high-speed C-level loop construction: [x**2 for x in range(10) if x % 2 == 0] creates [0, 4, 16, 36, 64].
Copying Semantics Aliasing vs. Shallow vs. Deep Copy b = a (Aliasing, same memory ID). b = a.copy() or a[:] (Shallow copy: outer list new, inner nested objects shared). import copy; b = copy.deepcopy(a) (Recursively duplicates all nested objects).
4.4 Tuples (tuple): Immutable Safety & Tuple Packing/Unpacking

Tuples are immutable sequence collections delimited by parentheses (). A singleton tuple requires a mandatory trailing comma: t = (42,) (without the comma, t = (42) evaluates as integer 42).

  • Tuple Packing & Unpacking: Assigning comma-separated values packs them into a tuple: point = 10, 20. Unpacking binds tuple elements into distinct variables: x, y = point. Python uniquely supports variable swapping without temporary variables via tuple packing/unpacking: a, b = b, a.
  • Architectural Advantages of Tuples: Tuples exhibit lower memory overhead than lists because their size is fixed at allocation. Because tuples are immutable, they are hashable (provided all contained items are hashable) and can serve as dictionary keys (e.g., coordinate pairs {(0, 0): 'Origin'}).

5. Hashable Collections: Dictionaries & Mathematical Set Theory

5.1 Dictionaries (dict): Hash Table Mechanics & Key Invariant Rules

A Python dictionary is an associative, mutable mapping of unique keys to values, implemented internally as an optimized, open-addressing hash table. In Python 3.7+, dictionaries are guaranteed to maintain insertion order.

The Absolute Invariant of Dictionary Keys:

A dictionary key must be an immutable, hashable object implementing hash() and eq(). Strings, numbers, and tuples of primitives make valid keys. Mutable objects (lists, sets, other dictionaries) cannot serve as keys because changing their state would mutate their hash value, breaking lookup integrity in the hash table bucket array.

Core Dictionary Methods & Computational Idioms:

  • d.get(key, default=None): Retrieves value for key safely without raising KeyError if the key is absent.
  • d.setdefault(key, default): Returns existing value if key is present; otherwise inserts key with value default and returns it.
  • d.pop(key, [default]): Removes specified key and returns its value; raises KeyError if missing and no default provided.
  • d.popitem(): Removes and returns the last inserted key-value pair as a 2-tuple in $O(1)$ time.
  • d.update(other_dict): Merges key-value pairs from another mapping, overwriting conflicting keys.
  • d.keys(), d.values(), d.items(): Return dynamic dictionary view objects that reflect runtime mutations immediately.
  • Dictionary Comprehensions: {k: v for k, v in iterable if condition} enables elegant data transformation (e.g., {x: x**3 for x in range(5)}).
5.2 Sets (set) & Mathematical Set Algebra

A set is a mutable, unordered collection of unique, hashable elements. An empty set must be instantiated using set(); using {} creates an empty dictionary.

Set Operation Operator Syntax Method Syntax Mathematical Meaning ($A, B$)
Union A | B A.union(B) All unique elements belonging to $A$ or $B$ ($A \cup B$).
Intersection A & B A.intersection(B) Common elements belonging to both $A$ and $B$ ($A \cap B$).
Difference A - B A.difference(B) Elements in $A$ that do not exist in $B$ ($A \setminus B$).
Symmetric Difference A ^ B A.symmetric_difference(B) Elements in $A$ or $B$, but not in both ($(A \cup B) \setminus (A \cap B)$).
Subset / Superset A <= B, A >= B A.issubset(B), A.issuperset(B) Boolean tests determining containment hierarchy.

6. Modular Functions, LEGB Scope, Persistent File I/O & Exceptions

6.1 Modular Functions, Argument Protocols & The LEGB Scope Hierarchy

Functions in Python are first-class citizens—they can be assigned to variables, passed as arguments, and returned from other functions.

  • Parameter Categories:
    • Positional Arguments: Matched strictly by position from left to right.
    • Keyword Arguments: Passed explicitly as name=value; can appear in any order following positional arguments.
    • Default Arguments: Parameters assigned default values (e.g., def calc(rate=0.05):). Rule: Non-default parameters cannot follow default parameters.
    • Variable-Length Arguments: *args collects excess positional arguments into a tuple; **kwargs collects excess keyword arguments into a dictionary.
  • The LEGB Scope Lookup Rule: When a variable is referenced within a function, Python resolves its identifier through four hierarchical scopes:
    1. L (Local): Names assigned within the current function body.
    2. E (Enclosing): Names in outer nested functions (examined from nearest to furthest).
    3. G (Global): Names defined at the module top level or declared via the global keyword.
    4. B (Built-in): Pre-loaded language names (e.g., len, range, print, ValueError).
  • The global and nonlocal Keywords: Assigning to an outer variable inside a function binds it to Local scope by default. To modify a global variable, use global var_name. In nested closures, to modify a variable in the enclosing outer function, use nonlocal var_name.
6.2 Persistent File I/O Architecture & Context Managers

Python handles secondary storage files through file stream objects. Best practice dictates using the Context Manager syntax (with open(...) as f:), which guarantees that file handles are safely closed even if exceptions occur:

File Mode Stream Nature Pointer Initial Position Behavior If File Does Not Exist
'r' Read Only (Text) Beginning (Offset 0) Raises FileNotFoundError.
'w' Write Only (Text) Beginning (Truncates file to 0 bytes) Creates new file.
'a' Append Only (Text) End of File (EOF) Creates new file.
'r+' Read and Write (Update) Beginning (Does not truncate) Raises FileNotFoundError.
'rb' / 'wb' Binary Streams Byte-level offset Used with pickle.dump() and pickle.load() for object serialization.

File Pointer Navigation: f.tell() returns the current byte position within the file. f.seek(offset, whence) repositions the pointer: whence=0 (relative to beginning), whence=1 (relative to current position), whence=2 (relative to end of file).

6.3 Robust Exception Handling Architecture

Exceptions represent runtime error states that disrupt normal execution. Rather than crashing abruptly, Python applications intercept and resolve anomalies through the complete four-part try...except...else...finally architecture:

# Comprehensive Four-Clause Exception Handling Pattern
try:
    file = open("records.txt", "r")
    val = int(file.readline().strip())
    result = 1000 / val
except FileNotFoundError as fnf_err:
    print(f"Log: Target file missing: {fnf_err}")
except ZeroDivisionError:
    print("Log: Denominator cannot be zero in calculation.")
except ValueError:
    print("Log: File content could not be parsed to integer.")
else:
    # Executes ONLY if try block succeeded without exceptions
    print(f"Success: Computed result = {result:.4f}")
finally:
    # Executes UNCONDITIONALLY (whether exceptions were raised, caught, or unhandled)
    try:
        file.close()
        print("Cleanup: File handle closed safely.")
    except NameError:
        pass

Key Programming Syntax, Statements & Translator Rules

Source Code (.py) -> AST -> Bytecode (.pyc) -> PVM (ceval.c) -> Hardware Execution
seq[start : stop : step] | Length = max(0, ceil((stop - start) / step))
Mutable: {list, dict, set} | Immutable: {int, float, complex, bool, str, tuple, frozenset}
Local (L) -> Enclosing (E) -> Global (G) -> Built-in (B)
'r' (Read), 'w' (Truncate/Write), 'a' (Append), 'r+' (Update/Read-Write), 'b' (Binary Flag)
try -> (except on error) | (else on no error) -> finally (always executes)

Conceptual Solved Examples & Case Studies

Example 1
Differentiate between mutable and immutable data types in Python with reference to memory management. Predict the exact output and explain why the second print statement yields the observed result: [2 Marks] a = [1, 2, 3] b = a a.append(4) print(b) x = 10 y = x x += 5 print(y)
Step-by-Step Solution:

Step 1: Conceptual Distinction (1 Mark) In Python, an object's mutability determines whether its in-memory state can be modified in-place without altering its memory identity (id()). Mutable types (e.g., list, dict, set) allow in-place modification on the heap. Immutable types (e.g., int, float, str, tuple) cannot have their internal state altered; any operation that modifies their value instantiates a brand-new object on the heap.

Step 2: Execution Trace & Code Analysis (1 Mark)

  1. 'a = [1, 2, 3]': A list object is created at memory address M1, and 'a' references M1. 'b = a': The reference M1 is assigned to 'b' (aliasing). Both 'a' and 'b' reference the exact same list. 'a.append(4)': In-place mutation modifies list M1 to [1, 2, 3, 4]. 'print(b)': Outputs [1, 2, 3, 4].

  2. 'x = 10': Integer object 10 is created at M2; 'x' references M2. 'y = x': 'y' references M2. 'x += 5': Because integers are immutable, Python cannot modify 10 in-place. It creates a new integer 15 at M3 and rebinds 'x' to M3. 'y' continues referencing M2. 'print(y)': Outputs 10.

Final Output: [1, 2, 3, 4] 10

Example 2
Given the string s = 'WBCHSE_COMPUTER_SCIENCE_2026', evaluate the exact outputs of the following slicing and method expressions with step-by-step mathematical index justification: [3 Marks] (a) s[7:15] (b) s[::-3] (c) s.split('_')[1].lower()
Step-by-Step Solution:

Evaluation Step-by-Step:

(a) Evaluating s[7:15]: [1 Mark]

  • Formula: s[start:stop] extracts characters from index 7 up to index 14 inclusive (stop 15 is excluded).
  • Index mapping of 'WBCHSE_COMPUTER_SCIENCE_2026': Index 7 = 'C', 8 = 'O', 9 = 'M', 10 = 'P', 11 = 'U', 12 = 'T', 13 = 'E', 14 = 'R'.
  • Result: 'COMPUTER'

(b) Evaluating s[::-3]: [1 Mark]

  • Formula: Negative step (-3) signifies reverse traversal starting from the final character s[-1] at index 28 down to start.
  • Sequence indices traversed: 28, 25, 22, 19, 16, 13, 10, 7, 4, 1.
  • Characters extracted: Index 28 = '6' Index 25 = '0' Index 22 = 'E' Index 19 = 'I' Index 16 = '_' Index 13 = 'E' Index 10 = 'P' Index 7 = 'C' Index 4 = 'S' Index 1 = 'B'
  • Result: '60EI EPC SB' -> '60EI_EPCSB'

(c) Evaluating s.split('_')[1].lower(): [1 Mark]

  • 's.split('_')' decomposes string by underscore into list: ['WBCHSE', 'COMPUTER', 'SCIENCE', '2026'].
  • Index [1] accesses the second element: 'COMPUTER'.
  • '.lower()' transforms string to lowercase: 'computer'.
  • Result: 'computer'
Example 3
Write a complete Python function 'char_frequency(text)' that takes a string, sanitizes it by removing all spaces and punctuation, converts all characters to lowercase, and utilizes a dictionary to compute and return the frequency count of each unique alphabetical character. Also provide a sample call. [3 Marks]
Step-by-Step Solution:

Model Python Code:

def char_frequency(text): """ Calculates frequency count of unique alphabetic characters. Returns a dictionary of format {char: count}. """ freq_dict = {} for char in text.lower(): if char.isalpha(): # Filter only alphabetic characters # Use dict.get(key, default) for O(1) frequency tallying freq_dict[char] = freq_dict.get(char, 0) + 1 return freq_dict

Sample Driver Call

sample_input = 'Python Class 12 WBCHSE!' output = char_frequency(sample_input) print(output)

Execution Trace & Marking Rubric:

  • Traversal & Case Normalization: Text is converted to lowercase via '.lower()' (1 Mark).
  • Character Filtering & Membership Validation: 'char.isalpha()' discards spaces, digits ('1', '2'), and punctuation ('!') (1 Mark).
  • Dictionary Update Idiom: 'freq_dict.get(char, 0) + 1' correctly initializes unseen keys to 0 and increments tally without raising KeyError (1 Mark).
  • Sample Output for 'Python Class 12 WBCHSE!': {'p': 1, 'y': 1, 't': 1, 'h': 2, 'o': 1, 'n': 1, 'c': 2, 'l': 1, 'a': 1, 's': 3, 'w': 1, 'b': 1, 'e': 1}
Example 4
(a) Construct a nested list comprehension that generates the transpose of an M x N matrix represented as a list of lists. [2 Marks] (b) Using list comprehension, write a one-line expression to extract all prime numbers from the range 2 to 50 inclusive. [2 Marks]
Step-by-Step Solution:

Solution (a): Matrix Transposition via Nested List Comprehension [2 Marks]

Given matrix: A list of rows, where matrix[i][j] represents row i, column j. Transposed matrix: Row j contains matrix[i][j] for all rows i.

Matrix Definition (3 x 4 matrix)

matrix = [ [1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12] ]

One-Line Transpose Comprehension:

transposed = [[row[col] for row in matrix] for col in range(len(matrix[0]))] print(transposed)

Output: [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

Marking: Correct outer loop over columns 'range(len(matrix[0]))' (1 Mark); correct inner extraction 'row[col] for row in matrix' (1 Mark).


Solution (b): Prime Number Generation via List Comprehension [2 Marks]

One-Line Prime Filter Expression:

primes = [n for n in range(2, 51) if all(n % d != 0 for d in range(2, int(n**0.5) + 1))] print(primes)

Output: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]

Marking: Range boundaries 2 to 51 (1 Mark); nested 'all()' generator testing factor divisibility up to sqrt(n) (1 Mark).

Example 5
Write a complete, production-grade Python script that performs the following file-processing tasks using context managers ('with open'): [4 Marks] 1. Reads an existing text file 'input_log.txt'. 2. Computes the total number of lines, total word count, and total character count (excluding newline characters). 3. Identifies and prints all unique lines starting with the prefix 'ERROR:'. 4. Robustly handles 'FileNotFoundError' and generic 'IOError' with informative diagnostic messages.
Step-by-Step Solution:

Model Python Script:

def analyze_log_file(filename): total_lines = 0 total_words = 0 total_chars = 0 error_lines = set()

try:
    with open(filename, 'r', encoding='utf-8') as f:
        for line in f:
            total_lines += 1
            stripped_line = line.rstrip('\r\n')
            total_chars += len(stripped_line)
            words = stripped_line.split()
            total_words += len(words)
            
            if stripped_line.startswith('ERROR:'):
                error_lines.add(stripped_line)

    print(f'=== Log File Analysis: {filename} ===')
    print(f'Total Lines: {total_lines}')
    print(f'Total Words: {total_words}')
    print(f'Total Characters: {total_chars}')
    print(f'Unique Error Entries Found ({len(error_lines)}):')
    for err in sorted(error_lines):
        print(f'  - {err}')

except FileNotFoundError:
    print(f'[CRITICAL ERROR]: Target file "{filename}" does not exist.')
except IOError as io_err:
    print(f'[I/O ERROR]: Operating system error reading "{filename}": {io_err}')

Driver Call

analyze_log_file('input_log.txt')

Marking Scheme Rubric:

  • Proper context manager usage 'with open(..., 'r')' guaranteeing automated closing (1 Mark).
  • Correct calculation of line count, character count, and word count using line iteration (1 Mark).
  • Accurate detection and unique set storage of 'ERROR:' lines (1 Mark).
  • Structured exception handling with distinct FileNotFoundError and IOError blocks (1 Mark).
Example 6
Design a Python module containing a statistical analysis function 'compute_summary(*data, **options)' that meets the following engineering specifications: [5 Marks] 1. Accepts any arbitrary count of numerical values via '*data'. 2. Accepts keyword arguments via '**options', supporting 'precision' (default 2) and 'outlier_threshold' (default None). 3. If no numerical arguments are passed, raises a custom user-defined exception 'EmptyDatasetError' with the message 'Dataset cannot be empty'. 4. Calculates and returns a dictionary containing 'count', 'mean', 'variance', and 'standard_deviation'. 5. Includes a 'try...except...finally' driver block demonstrating valid execution and exception trapping.
Step-by-Step Solution:

Comprehensive Python Implementation:

Step 1: Define Custom Exception

class EmptyDatasetError(Exception): """Custom Exception raised when mathematical dataset is empty.""" pass

Step 2: Implement Function with *args and **kwargs

def compute_summary(*data, **options): # Validate non-empty data if not data: raise EmptyDatasetError('Dataset cannot be empty.')

# Validate numeric types
for x in data:
    if not isinstance(x, (int, float)):
        raise TypeError(f'All elements must be numerical. Found invalid value: {x}')
        
precision = options.get('precision', 2)
n = len(data)
mean_val = sum(data) / n
variance_val = sum((x - mean_val) ** 2 for x in data) / n
std_dev = variance_val ** 0.5

return {
    'count': n,
    'mean': round(mean_val, precision),
    'variance': round(variance_val, precision),
    'standard_deviation': round(std_dev, precision)
}

Step 3: Driver Block with Robust Exception Handling

def main(): test_cases = [ (12, 18, 25, 30, 35, 42), (), # Triggers EmptyDatasetError (10, 'invalid', 30) # Triggers TypeError ]

for idx, tc in enumerate(test_cases, 1):
    print(f'\n--- Running Test Case {idx} ---')
    try:
        summary = compute_summary(*tc, precision=3)
        print(f'Calculation Succeeded: {summary}')
    except EmptyDatasetError as e:
        print(f'[CAUGHT]: {e}')
    except TypeError as e:
        print(f'[CAUGHT]: {e}')
    finally:
        print(f'Test case {idx} evaluation finalized.')

if name == 'main': main()

Marking Scheme Rubric (5 Marks Total):

  • Custom Exception Class Declaration: Subclassing Exception properly (1 Mark).
  • Signature & Argument Parsing: Correct usage of *data and **options.get('precision', 2) (1 Mark).
  • Empty Dataset Validation: Raising EmptyDatasetError when not data (1 Mark).
  • Accurate Mathematical Formulas: Correct implementation of mean, variance, and standard deviation (1 Mark).
  • Complete Driver Block: Functional try...except...finally block testing normal and exceptional execution paths (1 Mark).

Common Misconceptions & Examiner Traps

Common Misconception

The Mutable Default Argument Bug: def append_to(element, target_list=[])

Scientific Reality & Correction

Always use 'None' as the default sentinel value: def append_to(element, target_list=None): if target_list is None: target_list = []

Common Misconception

Conflating Identity ('is') with Value Equality ('==')

Scientific Reality & Correction

Always use '==' for value comparison. Reserve 'is' exclusively for singleton checks (e.g., 'if var is None:').

Common Misconception

Mutating a List While Iterating Over It Directly with a 'for' Loop

Scientific Reality & Correction

Iterate over a shallow copy of the list: 'for item in my_list[:]:' or construct a new filtered list using comprehension: 'my_list = [x for x in my_list if condition]'.

Common Misconception

Off-by-One Boundary Errors in range() and Sequence Slices

Scientific Reality & Correction

To include number N in an iteration, always set stop to N + 1: 'for i in range(1, 11):' generates integers 1 through 10.

Common Misconception

File Pointer Exhaustion After a Single read() Invocation

Scientific Reality & Correction

Reposition the file pointer back to the beginning before re-reading using 'file.seek(0)'.

Visual Learning & Conceptual Map

PROGRAMMING IN PYTHON : ARCHITECTURAL & RUNTIME ENGINE WBCHSE Class 12 Computer Science (Chapter 1) — Execution Pipeline, Memory Model & Flow WBCHSE CS • CH 1 Stage 1: CPython Compilation & Bytecode Virtual Machine Source Code to Bytecode & Stack-Based PVM Execution • Source script (.py) parsed to AST -> CPython bytecode compilation • Intermediate bytecode stored in cached .pyc files (pycache) • Python Virtual Machine (PVM) interprets bytecode to CPU instructions • Cross-platform portability: 'Write once, interpret anywhere' model Q1 Stage 2: Dynamic Typing, References & Object Mutability Reference Pointers, Garbage Collection & Mutability Matrix • Variables are typed object references; variable names are label tags • Mutable Objects: list, dict, set (in-place state mutation allowed) • Immutable Objects: int, float, str, tuple (modifications create new IDs) • Memory identity inspection with id(), type(); '==' vs 'is' identity Q2 CORE PYTHON COMPUTATIONAL ENGINE: INTERPRETED • DYNAMIC • OBJECT-ORIENTED BYTECODE (.pyc) • PVM ENGINE • DYNAMIC TYPING • LEGB SCOPE • RESILIENT I/O Stage 3: Sequence Containers & Hash Mappings Indexing, Slicing Strides & Comprehension Expressions • Bidirectional indexing & slicing: seq[start:stop:step], seq[::-1] • Tuple packing/unpacking; dict key hashability (keys must be immutable) • High-performance list, dict, and set comprehension syntax • Set theory algebra: Union (|), Intersection (&), Symmetric Diff (^) Q3 Stage 4: Modular Functions, File Streams & Exceptions LEGB Scope, Context Managers & Robust Try-Except Blocks • Function mechanics: Positional, Keyword, Default, *args, and **kwargs • Scope lookup hierarchy: Local -> Enclosing -> Global -> Built-in (LEGB) • Resource-safe file I/O with 'with open(...) as f:' and pickle streams • Structured error handling: try...except...else...finally constructs Q4

Check Your Understanding (Diagnostic Practice Questions)

Diagnostic questions testing core conceptual clarity. Answers are hidden initially — solve each problem first, then click to reveal the step-by-step verified solution.

1
Predict the output of the following code snippet and explain the underlying reason: def modify(x, lst=[]): lst.append(x) return lst print(modify(1)) print(modify(2, [])) print(modify(3))
Reveal Answer & Explanation
Answer: Output: [1] [2] [1, 3] Explanation: In the first call modify(1), the default list is populated with 1, yielding [1]. In the second call modify(2, []), a new explicit list [] is passed, so the default list is untouched and [2] is returned. In the third call modify(3), the default list is used again, which already contains [1]; appending 3 yields [1, 3].
Default arguments are evaluated once at function definition time. Notice when an explicit empty list is supplied versus when the default is used.
2
What is the difference between shallow copy and deep copy in Python? Provide an example where a shallow copy produces unexpected side effects.
Reveal Answer & Explanation
Answer: A shallow copy (e.g., b = a.copy() or b = a[:]) creates a new outer collection, but populates it with references to the child objects of the original. A deep copy (copy.deepcopy(a)) recursively duplicates all child objects. Example: a = [[10, 20]]; b = a.copy(); b[0].append(30); print(a) outputs [[10, 20, 30]] because both a[0] and b[0] reference the same inner list.
Consider a list containing another nested list, such as a = [[1, 2], [3, 4]]. What happens to the inner list when modified?
3
Explain why the expression (5,) is a tuple, whereas (5) is an integer in Python.
Reveal Answer & Explanation
Answer: In Python, parentheses are used both for tuple syntax and for arithmetic operator grouping (e.g., (2 + 3) * 5). To disambiguate, Python requires a trailing comma for single-element tuples: (5,) creates a tuple containing integer 5, whereas (5) is treated as the grouped integer expression 5.
Parentheses in Python also serve as arithmetic grouping delimiters.
4
Write a Python expression using dictionary comprehension to invert a dictionary 'd = {"a": 1, "b": 2, "c": 3}' so that values become keys and keys become values.
Reveal Answer & Explanation
Answer: inverted_dict = {value: key for key, value in d.items()} Result: {1: 'a', 2: 'b', 3: 'c'}. Note: This assumes all values in the original dictionary are unique and hashable.
Iterate over d.items() and unpack key and value in reversed order.
5
What is the exact purpose of the 'finally' clause in Python exception handling? Can 'finally' execute even if a 'return' statement is encountered in the 'try' block?
Reveal Answer & Explanation
Answer: The 'finally' clause defines cleanup actions that must execute under all circumstances, whether an exception was raised, handled, or unhandled. Yes, even if a 'return' statement is reached in the 'try' or 'except' block, the 'finally' block is guaranteed to execute immediately before the function actually exits and returns.
Consider runtime guarantees for external resource deallocation.
Finished Studying This Chapter?
READY TO PRACTICE?

Timed CBT Practice Tests (Exam Simulator)

Put your concepts to the test with official curriculum-aligned Foundation and Advanced practice tests. Get instant accuracy scores, time metrics, and step-by-step verified explanations.

STAY UPDATED

Get the Latest Updates

New test series, syllabus updates, exam notifications and more.

Syllabus
Updates
Exam
Alerts
Study
Resources