Registry Synced

prepguide

3549 words
18 min read
This guide provides a comprehensive "Ground-Up" theoretical foundation of Python, combined with the practical mechanics needed to write, simulate, and successfully pass OPPE graded coding assignments for the IITM BS Degree.

Part 0: Visualizations & Mental Models

Before writing code, you need a mental model of how Python evaluates your logic. Below are visualization flows of how Python natively processes data in memory.

Variable Assignment (References, not Boxes)

Unlike C or Java where variables are "boxes" holding values, in Python, Variables are sticky notes attached to objects in memory.
Architect Mode
Building Architecture Diagram...
If x = 5 and y = x, both sticky notes point to the same 5. If x = 10, x peels off 5 and sticks to 10. y is completely unaffected!

Control Flow (The Loop Engine)

Architect Mode
Building Architecture Diagram...

Part 1: Core Theory & Jargon (The Lexicon)

1. Primitives vs Composites

  • Primitives (Immutable): These are the atomic building blocks of Python. Once created, their value in memory cannot be changed. If you modify them, Python destroys the old one and generates a new one.
    • int: Whole numbers (5, -10).
    • float: Decimals (3.14). Precision can sometimes drift (e.g., 0.1 + 0.2 != 0.3).
    • bool: Truth states (True, False). Internally, these are just 1 and 0.
    • str: Strings of characters ("IITM"). Strings are technically sequences and are immutable.
  • Composites (Data Structures): Objects that hold multiple Primitives.
    • list ([]): Ordered, Mutable sequence. You can change elements at will.
    • tuple (()): Ordered, Immutable sequence. Locked permanently after creation.
    • dict ({}): Unordered (historically mapping, now insertion-ordered), Mutable key-value pairs.
    • set ({}): Unordered, Mutable collection of theoretically unique elements.

2. Operators Theory & Minute Tacit Details

  • Arithmetic: +, -, *, / (always returns float), // (Floor division - truncates decimals), % (Modulo - returns remainder), ** (Exponentiation).
  • Relational (Comparison): Evaluates to Booleans. == (Equality), != (Not Equal), >, <, >=, <=.
  • Logical: and (True if BOTH are true), or (True if AT LEAST ONE is true), not (Inverts truth).
Fact: Python uses "Short-circuit evaluation". For A and B, if A is False, Python doesn't even bother evaluating B because the whole statement is guaranteed to be False.
  • Arithmetic Operators:
    • / (Standard Division): Always returns a Float (even 4/2 is 2.0).
    • // (Floor Division): Performs division and rounds down to the nearest integer less than or equal to the quotient (toward negative infinity). Discards the fractional part.
      • Example (Tacit Detail): 10 // 3 is 3, but -10 // 3 is -4 (rounds toward more negative).
    • % (Modulo): Returns the remainder. Used for even/odd testing (x % 2 == 0).
    • ** (Exponentiation): 2**3 is 8.
  • Built-in Numeric "GOTCHAS" (IITM MCQ Favorites):
    • The Rounding Rule: round(x) in Python 3 uses Banker's Rounding. It rounds to the nearest even number on a .5 boundary.
      • Example: round(2.5) is 2, but round(3.5) is 4.
    • Implicit Boolean Truthiness: Almost every object has a boolean value.
      • 0, 0.0, "" (Empty String), [] (Empty List), {} (Empty Dict), None are all False.
      • Literally everything else is True.
  • Logical Operators:
    • and (True if BOTH true), or (True if ANY true), not (Inverts).
    • Fact: Python uses "Short-circuit evaluation". For A and B, if A is False, Python doesn't evaluate B.

3. Iterables and Iterators

  • Iterable: Any object capable of returning its members one at a time (Strings, Lists, Dictionaries).
  • Iteration: The physical process of taking one element at a time from an iterable (e.g., running a for loop).

Part 2: OPPE Evaluation Mechanics

Before writing a single line of logic, you must identify how the IITM portal is executing your code. There are exactly 3 pipeline structures tested in the exam. Failing to match the pipeline structure will fail all test cases natively.

1. Standard I/O (The Loop Input Pattern)

Most fundamental questions require you to repeatedly accept dynamic input from the server. Your Job: Catch it with input(), cast its type, process it, and EXCLUSIVELY print() the answer. No debug text.
python
num_lines = int(input())   # Server passes the count of datasets
for _ in range(num_lines):
    data = input()          # Server passes N sequential string payloads
    print(data.upper())     # Print result verbatim!

2. Functional Injection (The Skeleton Pattern)

The problem explicitly locks you into a predefined function signature: def find_vowels(word: str) -> str: Your Job: The system injects a hidden harness that calls your function generically, comparing against expected text. Do not use input(). Do not use print(). Use return.
python
def reverse_substring(s: str) -> str:
    # Process the argument directly
    return s[::-1]

3. State Evaluation (Variable Checking - e.g. GrPA 2)

The problem contains locked Variable mappings: output1 = .... Your Job: Assign the literal value string logically. The grader strictly evaluates the value hosted in the isolated output1 memory block.

Part 3: Core Manipulation Hacks & Procedures

The String Slicing Formula [start:stop:step]

This is universally tested. Strings are strictly immutable in Python!
  • start: Inclusive limit. Default is 0.
  • stop: Exclusive limit. Default is len(word).
  • step: Interval leap. Default is 1.
Cheatsheet:
python
s = "IITMadras"
s[::-1]        # "sardaMTII" (Strict Reverse)
s[::2]         # "ITars" (Every Even Index)
s[1::2]        # "IMda" (Every Odd Index)
s[:-1]         # Drops the last character

Enumeration & Zip

When iterating over sequences, if you need both the index position AND the active element, never write a raw range(len(x)) block! Be pythonic:
python
word = "Python"
for index, char in enumerate(word):
    if index % 2 == 0:
        print(f"Index {index}: {char}")
If you are iterating over two parallel lists simultaneously:
python
listA = [1, 2, 3]
listB = ["A", "B", "C"]
for num, char in zip(listA, listB):
    print(num, char) # Evaluates in exact positional parity

Part 4: Nested Execution Spaces (Week 3 Dynamics)

Nested Loops conceptually run an entire inner iteration cycle for every single increment of the outer iteration cycle.
Example Matrix Mapping:
python
for r in range(3):        # Outer loop controls Rows (0, 1, 2)
    for c in range(3):    # Inner loop controls Columns (0, 1, 2)
        print(f"[{r},{c}]", end=" ")
    print()               # Line break after an entire row of columns finishes

Break vs Continue

  • continue: Instantly aborts the current inner loop cycle and triggers the next cycle of that exact loop.
  • break: Completely destroys and exits the active loop layer permanently. (If placed in an inner loop, it only breaks the inner loop, leaving the outer loop running!).

Part 5: HashMaps (The Frequency Counter Pattern)

The most consistent OPPE logic pattern involves counting or restructuring unique element arrays securely using Dictionaries ({}).
The Classic Frequency Algorithm: You are given a list of raw items and must map their individual occurrences without collapsing duplicates.
python
inbox = ["apple", "banana", "apple", "orange", "banana", "apple"]
frequency_map = {}

for fruit in inbox:
    if fruit not in frequency_map:
        frequency_map[fruit] = 1   # Initialize the key
    else:
        frequency_map[fruit] += 1  # Increment existing mapping

# frequency_map -> {"apple": 3, "banana": 2, "orange": 1}

Set Reductions

If you only need unique elements without tracking quantities, cast to a set. Operations over Sets natively execute geometric relationships.
python
a = {1, 2, 3}
b = {3, 4, 5}
a & b   # Intersection -> {3}
a | b   # Union -> {1, 2, 3, 4, 5}
a - b   # Difference -> {1, 2}
a ^ b   # Symmetric Diff -> {1, 2, 4, 5}

Part 6: Function Mechanics & Scoping

Arguments vs Parameters

  • Parameter: The variable listed inside the parentheses in the function definition (e.g. def test(a, b):).
  • Argument: The actual value that is sent to the function when it is called (e.g. test(5, 10)).

Variable Scope (LEGB Rule)

When you call a variable, Python investigates memory in this precise order:
  1. Local: Inside the current function.
  2. Enclosing: Inside any overarching wrapper functions.
  3. Global: At the top level of the module/script.
  4. Built-in: Python's native reserved keywords (len, sum, print).

Note: If you want to modify a Global variable inside a Local scope, you must explicitly declare global x inside the function, otherwise Python creates a shadowing Local copy.

Part 7: Edge-Case Formatting

If your Test Run simulator catches a Private Case output failure, visualize the extremities:
  1. Empty Buffers: Did you account for s = "" or arr = []? Don't blindly slice s[0].
  2. Endings: Does your output natively inject \n linebreaks incorrectly? Use print(ans, end="") to suppress implicit newlines.
  3. Format Alignment: If an expected integer needs padding: f"{num:02d}" automatically pads 5 into 05.
  4. String Immutability Pitfall: You cannot do string[0] = 'a'. You must build a new string: new_string = 'a' + string[1:].

Part 8: Advanced Minute Details & "Gotchas"

This section covers the extremely tacit logic that separates a passing grade from a 100/100.

1. Equality (==) vs. Identity (is)

  • ==: Compares Values. If they look consistent, it returns True.
  • is: Compares Memory Locations (id()).
  • Tact Detail: 2 == 2.0 is True, but 2 is 2.0 is False (one is an int object, one is a float object).

2. Search Methods: find() vs index()

Both find the position of a substring, but handle failure differently:
  • string.find("x"): Returns -1 if "x" is not found. (Best for safe if checks).
  • string.index("x"): Raises a ValueError (crashes code) if "x" is not found.

3. Shallow Copy Trap (* with Lists)

When you create a list of lists using multiplication, Python copies the Reference, not the data.
python
matrix = [0](/viewer?path=0) * 3  # Looks like [0], [0], [0](/viewer?path=0], [0], [0)
matrix[0][0] = 1    # BEWARE: This changes ALL sublists!
# Result: [1], [1], [1](/viewer?path=1], [1], [1)
Procedure Tip: Always use a list comprehension for safe matrices: [[0] for _ in range(3)].

4. The Mutable Default Argument Bug

Never use an empty list as a default parameter in a function!
python
def add_item(val, items=[]):
    items.append(val)
    return items

print(add_item(1)) # [1]
print(add_item(2)) # [1, 2] !!! (The list persists across calls)

5. String Methods Invariants

  • s.split(): If no delimiter is given, it splits by any whitespace (space, tab, newline) and discards empty strings.
  • s.strip(): Only removes whitespace from the ends of the string. It does nothing to spaces in the middle.

6. Mapping & Collection Invariants

  • Dictionary Keys: Must be Hashable (Immutable). You can use a tuple as a key, but never a list.
  • Set Membership: Checking if x in my_set is lightning fast (O(1)O(1)) compared to a list (O(N)O(N)). If you are doing thousands of lookups, convert your list to a set first!

Part 9: Canonical OPPE Question Patterns

Most OPPE questions follow one of these 5 logical "skeletons." If you recognize the pattern, the problem is 80% solved.

1. The Frequency Tally (The #1 Most Common Pattern)

Goal: Count occurrences of items (words, chars, numbers).
python
items = ["A", "B", "A", "C", "B", "A"]
tally = {}
for item in items:
    tally[item] = tally.get(item, 0) + 1 # Shortest way to handle initialization
# Find max frequency
most_common = max(tally, key=tally.get) 

2. Matrix Row/Column Sums

Goal: Process 2D Lists (Weeks 3-4).
python
matrix = [1, 2, 3], [4, 5, 6](/viewer?path=1, 2, 3], [4, 5, 6)
# Row Sums
row_sums = [sum(row) for row in matrix]
# Column Sums
col_sums = []
for c in range(len(matrix[0])):
    current_sum = 0
    for r in range(len(matrix)):
        current_sum += matrix[r][c]
    col_sums.append(current_sum)

3. The Running Accumulator (Min/Max/Avg)

Goal: Find an extremity without using min()/max() (Used in Standard I/O loops).
python
n = int(input())
res = None
for _ in range(n):
    val = int(input())
    if res is None or val > res: # Pattern for first-item assignment
        res = val
print(res)

4. The "Substring Sieve" (String Parsing)

Goal: Extract data from "Dirty" strings like ID:001|Name:Alice.
python
data = "ID:001|Name:Alice"
parts = data.split("|") # ['ID:001', 'Name:Alice']
for p in parts:
    key, val = p.split(":") # Split every pair again
    print(f"{key} is {val}")

5. Nested Loops: Coordinate Filter

Goal: Find neighbors in a 2D space or print specific shapes.
python
n = 5
for i in range(1, n + 1):
    # Print a right-angled triangle
    print("*" * i) 

6. Parity Filter (List Comprehension)

Goal: Clean a collection in one line.
python
raw = [1, 5, 8, 12, 13]

Part 10: The Mental Blueprint Mapping

When you read a question, use this table to choose your "Blueprint" instantly.
If the question asks for...Use this Blueprint (Skeleton)
"Find most frequent..."Pattern 1: Dictionary .get(x, 0) + 1
"Sum of every column..."Pattern 2: Swapped indices matrix[r][c]
"Find highest/lowest..."Pattern 3: Running res = None if-check
"Extract names from list..."Pattern 4: `.split("
"Generate a triangular grid"Pattern 5: Inner loop bounded by outer index j in range(i)
"Discard all odd numbers"Pattern 6: List Comprehension [x for x in L if x % 2 == 0]
Pro Tip: If a question seems impossible, it’s usually just Pattern 1 hidden in a different scenario.

Part 14: Deep Dictionary & Collection Patterns

Dictionaries are the backbone of efficient Python programming. Mastering these patterns is the difference between a pass and a full score.

1. Dictionary Grouping (Parity/Categorization)

If you need to separate items into categories (e.g., even/odd, by first letter), use a dictionary of lists.
python
# Grouping numbers by parity
nums = [1, 2, 3, 4, 5, 6]
groups = {"even": [], "odd": []}

for x in nums:
    if x % 2 == 0:
        groups["even"].append(x)
    else:
        groups["odd"].append(x)

# Result: {"even": [2, 4, 6], "odd": [1, 3, 5]}

2. Dictionary Inversion (Keys ↔ Values)

Sometimes you need to find which "Key" belongs to a "Value."
python
d = {"apple": "fruit", "carrot": "vegetable"}
inverted = {}

for key, val in d.items():
    inverted[val] = key  # WARNING: Only works if values are unique!

# Result: {"fruit": "apple", "vegetable": "carrot"}

3. Collection Speed Patterns (Sets)

Sets are for Uniqueness and Speed. Membership checking (x in s) is nearly instantaneous.
python
# Remove duplicates while preserving order
lst = [1, 2, 2, 3, 1, 4]
seen = set()
unique_lst = []

for x in lst:
    if x not in seen:
        unique_lst.append(x)
        seen.add(x)

Part 15: The OPPE Readiness Kit

1. The "Second Largest" Algorithm (The Trap)

Finding the largest is easy. Finding the second largest requires careful logic to handle duplicates.
python
lst = [10, 20, 20, 15, 5]
mx = max(lst)
second_mx = None

for x in lst:
    if x != mx:  # Skip the absolute highest
        if second_mx is None or x > second_mx:
            second_mx = x
# Result: 15 (correctly skips the second 20)

2. The 1-Day Crash Revision Plan

  1. Hour 1-2: Review basic arithmetic, Banker's rounding, and floor division.
  2. Hour 3-4: Practice String/List slicing and the [start:stop:step] formula.
  3. Hour 5-6: Master Dictionary Frequency Counters and .get(x, 0) + 1.
  4. Hour 7-8: Solve 5 mock questions from scratch without autocomplete.

3. Mock OPPE Drill Questions (with Solutions)

Q1: Frequency Mapping

Input: A string "aabcab" Output: {'a': 3, 'b': 2, 'c': 1}
python
def char_frequency(s):
    freq = {}
    for char in s:
        freq[char] = freq.get(char, 0) + 1
    return freq

Q2: Palindrome Filter

Input: ["racecar", "hello", "madam", "step"] Output: ["racecar", "madam"]
python
def get_palindromes(words):
    # s[::-1] is the most efficient way to reverse
    return [w for w in words if w == w[::-1]]

Q3: Substring Parsing (The "Value Split")

Input: "temp:32|humidity:80|wind:10" Output: {'temp': '32', 'humidity': '80', 'wind': '10'}
python
def parse_data(s):
    res = {}
    parts = s.split("|") # Split into ['temp:32', 'humidity:80', ...]
    for p in parts:
        key, val = p.split(":") # Split every pair again
        res[key] = val
    return res

Q4: Nested List Flattening

Input: [1, 2], [3], [4, 5](/viewer?path=1, 2], [3], [4, 5) Output: [1, 2, 3, 4, 5]
python
def flatten(matrix):
    res = []
    for row in matrix:
        for item in row:
            res.append(item)
    return res

Part 16: Final Tacit "Gotcha" Cheat Sheet

FeatureBehavior
**round(2.5)**Returns 2 (Banker's rounding to even).
**-10 // 3**Returns -4 (Rounds toward negative infinity).
**"abc" * 0**Returns "" (Empty string).
**bool([])**Returns False (Empty collections are False).
**x is y**Checks memory ID, not the value. Always use == for values.
**s.find("z")**Returns -1 if missing.
**s.index("z")**Crashes code if missing.

Part 11: The "What to Write" Manual (Logic & Breakdown)

If you stare at a blank screen and don't know where to start, you are skipping the Input-Logic-Output (ILO) phase.

1. The ILO Framework

Every OPPE problem is a factory. You must define what comes in, what happens in the middle, and how it leaves.
StepQuestion to Ask YourselfPython Tool
InputIs the server giving me a string? A list? Numbers?input() or function parameters (def func(x):)
LogicDo I need to count? Filter? Transform? Search?for, if, while, map, filter
OutputDo I return the value or print it?return (skeleton) or print() (Standard I/O)

2. The def Contract

When you write def calculate_average(numbers):, you are signing a contract.
  • The Input (numbers): You trust this variable already exists. Don't redefine it inside!
  • The Body: Use the parameter numbers as if it's a real list holding data.
  • The End: If the instructions say "Return", you must use return result. Printing it won't pass.

3. Using the Underscore _

If you need to repeat something 10 times but don't care about the index number:
  • Don't write: for i in range(10): (unless you need i)
  • Do write: for _ in range(10):
  • Why? The _ tells Python (and you) "I just need the loop to run, I don't need the counter variable." This reduces mental clutter.

Part 12: Slicing, Dots, and Method Etiquette

1. The "Dot" (.) — Accessing Power

In Python, nearly everything is an Object. The dot is your key to that object's built-in superpowers (Methods).
  • **"hello".upper()**: You are telling the String object "Hey, use your upper power on yourself."
  • **my_list.append(5)**: You are telling the List object "Hey, use your append power to add 5."
Crucial Distinction:
  • String Methods (e.g., .replace(), .upper()) RETURN a new string. They never change the original.
  • List Methods (e.g., .append(), .sort(), .reverse()) CHANGE the original list directly (in-place) and return None.

2. Slicing Mastery [start:stop:step]

Think of a list/string like a loaf of bread. Slicing lets you take exactly the slices you want.
  • s[2:5] -> From index 2 up to (but not including) 5.
  • s[:3] -> From the very beginning up to 3.
  • s[4:] -> From 4 all the way to the end.
  • s[::-1] -> Step is negative, so start from the end and walk backward (Reverse).

3. "The Dots" vs "The Built-ins"

  • Methods (obj.method()): Specific to a type. [1,2].append(3) works, "abc".append("d") crashes!
  • Functions (func(obj)): Universal. len() works on strings, lists, dicts, and tuples.

Part 13: Coding Etiquette (Anti-Chaos Rules)

To stop your code from becoming "chaotic" during the heat of the 90-minute exam, follow these rules:
  1. Meaningful Variables (Names Matter):
  • a = [1, 2, 3]
  • price_list = [1, 2, 3]
  • If you name it price_list, you won't accidentally try to "capitalize" it later.
  1. Indentation is Logic:
  • In Python, space is not just for style; it defines where a block starts and ends.
  • Always check your alignment. If a print is under an if, it only runs if the if is True. If it's outside the if, it runs regardless.
  1. Mental Housekeeping:
  • If a problem asks for 3 things (Sum, Max, Min), solve them one by one.
  • Step 1: Get the sum working.
  • Step 2: Get the max working.
  • Step 3: Get the min working.
  • Step 4: Combine.
  1. The "Check" Habit:
  • Always run your code locally or in the simulator before submitting.
  • If Case 1 passes but Case 2 fails, look for Edge Cases (Empty inputs? Negative numbers? Large strings?).
  
Document Outline
Table of Contents
System Normal // Awaiting Context

Intelligence Hub

Navigate the knowledge graph to generate context. The Hub adapts dynamically to surface backlinks, related notes, and metadata insights.