Python Interview Preparation

Python Interview Preparation

Complete guide from zero to interview-ready. Har cheez bahut detail mein, simple language mein. 🚀

How to use this guide

Yeh guide bilkul beginning se start hoti hai. Agar tujhe loops nahi aate, koi baat nahi - yahan pe sab kuch step by step samjhaya gaya hai. Har concept ke saath code examples hain. Har coding question ka dry run (step by step trace) diya hai. Pehle padh, phir khud try kar, phir answer dekh.

Section 1: Python Basics

Foundation

Variables & Data Types

What is a Variable? (Variable kya hota hai?)

Variable ek container hai jisme tu koi bhi value store kar sakti hai. Jaise ek dabba (box) hota hai - usme tu kuch bhi rakh sakti hai. Python mein variable banane ke liye bas naam do aur value assign karo:

# Variable banane ka tarika - bas naam = value
name = "Shweta"        # yeh ek string (text) hai
age = 25                # yeh ek integer (number) hai
height = 5.4             # yeh ek float (decimal number) hai
is_student = True        # yeh ek boolean (True/False) hai

# Variable use karna
print(name)     # Output: Shweta
print(age)      # Output: 25
Remember

Python mein variable ka type batane ki zaroorat nahi hoti. Python khud samajh jaata hai ki "Shweta" text hai aur 25 number hai. Isko dynamic typing kehte hain.

Data Types (Python mein kitne type ke data hote hain?)

TypeKya hai?ExampleMutable?
intWhole numbers (poore number)10, -5, 0No
floatDecimal numbers3.14, -2.5No
strText (string)"hello", 'hi'No
boolTrue ya FalseTrue, FalseNo
listOrdered collection, changeable[1, 2, 3]Yes
tupleOrdered collection, NOT changeable(1, 2, 3)No
dictKey-value pairs{"name": "Shweta"}Yes
setUnique values only, unordered{1, 2, 3}Yes
# Type check karne ke liye type() function use karo
x = 10
print(type(x))       # <class 'int'>

y = "hello"
print(type(y))       # <class 'str'>

z = [1, 2, 3]
print(type(z))       # <class 'list'>

Type Conversion (Ek type se doosre type mein badalna)

# String ko integer mein badalna
num_str = "42"
num_int = int(num_str)     # ab yeh 42 number ban gaya

# Integer ko string mein badalna
age = 25
age_str = str(age)          # ab yeh "25" string ban gaya

# Integer ko float mein
x = float(10)               # 10.0

# Float ko integer mein (decimal part cut jaata hai)
y = int(3.9)                # 3 (round nahi hota, seedha cut)

# List ko set mein (duplicates remove)
my_list = [1, 2, 2, 3]
my_set = set(my_list)        # {1, 2, 3}

Mutable vs Immutable (Badal sakta hai ya nahi?)

Simple Explanation

Mutable = Jisko badal sakti hai creation ke baad (list, dict, set)
Immutable = Jisko badal NAHI sakti creation ke baad (int, float, str, tuple)

# LIST is Mutable - badal sakti hai
fruits = ["apple", "banana"]
fruits[0] = "mango"       # allowed! ab fruits = ["mango", "banana"]

# STRING is Immutable - badal NAHI sakti
name = "Shweta"
# name[0] = "P"              # ERROR! Strings cannot be changed
name = "Priya"              # yeh naya string assign hua, purana nahi badla

# TUPLE is Immutable
coords = (10, 20)
# coords[0] = 30             # ERROR! Tuples cannot be changed

Operators

Arithmetic Operators (Math wale)

a = 15
b = 4

print(a + b)     # 19   (addition / jod)
print(a - b)     # 11   (subtraction / ghata)
print(a * b)     # 60   (multiplication / guna)
print(a / b)     # 3.75 (division - hamesha float deta hai)
print(a // b)    # 3    (floor division - decimal hata deta hai)
print(a % b)     # 3    (modulus - remainder / bacha hua)
print(a ** b)    # 50625 (power - 15^4)
Interview Tip

// (floor division) aur % (modulus) bahut interview mein poochhe jaate hain. % se tujhe remainder milta hai - isse check kar sakti hai ki number even hai ya odd: num % 2 == 0 matlab even.

Comparison Operators (Compare karna)

x = 10
y = 20

print(x == y)    # False  (kya equal hai?)
print(x != y)    # True   (kya equal NAHI hai?)
print(x > y)     # False  (kya bada hai?)
print(x < y)     # True   (kya chhota hai?)
print(x >= y)    # False  (kya bada ya equal hai?)
print(x <= y)    # True   (kya chhota ya equal hai?)

Logical Operators (and, or, not)

age = 25
has_id = True

# and - DONO conditions True honi chahiye
print(age >= 18 and has_id)     # True (dono True hain)

# or - KOI EK condition True ho toh True
print(age < 18 or has_id)       # True (has_id True hai)

# not - ulta kar deta hai
print(not has_id)                  # False (True ka ulta = False)

is vs == (IMPORTANT Interview Question!)

# == checks VALUE (kya value same hai?)
# is checks IDENTITY (kya same object hai memory mein?)

a = [1, 2, 3]
b = [1, 2, 3]
c = a

print(a == b)    # True  (value same hai)
print(a is b)    # False (memory mein alag objects hain)
print(a is c)    # True  (c = a, toh same object ko point karte hain)
Interview mein yeh zaroor poochhenge!

== se value compare hoti hai. is se memory address compare hota hai. Small integers (-5 to 256) aur short strings ke liye Python caching karta hai, toh is True aa sakta hai, lekin rely mat karo - hamesha == use karo value check ke liye.

Strings

String Methods (String ke saath kya kya kar sakti hai)

text = "  Hello, Python World!  "

# Case change
print(text.upper())         # "  HELLO, PYTHON WORLD!  "
print(text.lower())         # "  hello, python world!  "
print(text.title())         # "  Hello, Python World!  "

# Spaces hatana
print(text.strip())         # "Hello, Python World!" (dono taraf se)
print(text.lstrip())        # "Hello, Python World!  " (left se)
print(text.rstrip())        # "  Hello, Python World!" (right se)

# Split aur Join
words = "apple,banana,cherry"
print(words.split(","))     # ['apple', 'banana', 'cherry'] (list ban gaya)

my_list = ["a", "b", "c"]
print("-".join(my_list))    # "a-b-c" (list se string ban gaya)

# Replace aur Find
msg = "I love Java"
print(msg.replace("Java", "Python"))  # "I love Python"
print(msg.find("love"))                # 2 (index jahan se "love" start hota hai)
print(msg.find("xyz"))                 # -1 (nahi mila)

# Check karna
print("hello".isalpha())    # True (sab letters hain)
print("123".isdigit())      # True (sab numbers hain)
print("hello".startswith("he"))  # True
print("hello".endswith("lo"))    # True

String Slicing (String ka kuch hissa lena)

# Syntax: string[start:end:step]
# start = kahan se (included)
# end = kahan tak (NOT included)
# step = kitne gap se

text = "PYTHON"
#        P  Y  T  H  O  N
# Index: 0  1  2  3  4  5
# Neg:  -6 -5 -4 -3 -2 -1

print(text[0])       # P (pehla character)
print(text[-1])      # N (last character)
print(text[0:3])     # PYT (index 0,1,2 - end included nahi)
print(text[2:])      # THON (index 2 se end tak)
print(text[:3])      # PYT (start se index 2 tak)
print(text[::2])     # PTO (har 2nd character)
print(text[::-1])    # NOHTYP (reverse!)

f-strings (Modern way to format strings)

name = "Shweta"
age = 25
score = 95.678

# f-string = f lagao quote ke pehle, {} mein variable daalo
print(f"My name is {name} and I am {age} years old")
# Output: My name is Shweta and I am 25 years old

# Calculation bhi ho sakti hai
print(f"Next year I will be {age + 1}")

# Decimal places control
print(f"Score: {score:.2f}")   # Score: 95.68 (2 decimal places)

Section 2: Loops (Bahut Detail Mein)

Most Important
Yeh section zyada dhyaan se padh!

Loops programming ka sabse important concept hai. Agar loops samajh aagaye toh baaki sab easy ho jaayega. Main har cheez real-world example ke saath samjhaaoongi.

for Loop

What is a Loop? (Loop kya hai?)

Real life mein socho: agar tujhe 100 students ko "Good Morning" bolna hai. Toh kya tu 100 baar likhegi?

# Bina loop ke - 100 baar likhna padega!
print("Good Morning Student 1")
print("Good Morning Student 2")
print("Good Morning Student 3")
# ... yeh toh pagalpan hai! 100 lines likhni padengi

# Loop ke saath - bas 2 lines!
for i in range(1, 101):
    print(f"Good Morning Student {i}")

Loop matlab: Ek kaam ko baar baar repeat karna, jab tak condition poori na ho jaaye.

Basic for loop syntax

# Syntax:
# for variable in sequence:
#     kaam karo (yeh indented hona chahiye)

# Example 1: List mein se ek ek item lena
fruits = ["apple", "banana", "cherry"]

for fruit in fruits:
    print(f"I like {fruit}")

# Output:
# I like apple
# I like banana
# I like cherry

# Kya ho raha hai?
# 1st round: fruit = "apple"   → print ho gaya
# 2nd round: fruit = "banana"  → print ho gaya
# 3rd round: fruit = "cherry"  → print ho gaya
# List khatam → loop bhi khatam

range() Function (Numbers generate karna)

# range(stop) - 0 se leke stop-1 tak
for i in range(5):
    print(i)       # 0, 1, 2, 3, 4  (5 nahi aayega!)

# range(start, stop) - start se leke stop-1 tak
for i in range(1, 6):
    print(i)       # 1, 2, 3, 4, 5

# range(start, stop, step) - step = kitne gap se
for i in range(0, 10, 2):
    print(i)       # 0, 2, 4, 6, 8  (even numbers)

# Reverse range (ulta ginti)
for i in range(5, 0, -1):
    print(i)       # 5, 4, 3, 2, 1

Looping Through Different Things

# 1. Loop through a STRING (har character ek ek karke)
for char in "HELLO":
    print(char)    # H, E, L, L, O

# 2. Loop through a DICTIONARY
student = {"name": "Shweta", "age": 25, "city": "Delhi"}

# Sirf keys
for key in student:
    print(key)     # name, age, city

# Keys aur values dono
for key, value in student.items():
    print(f"{key}: {value}")
    # name: Shweta
    # age: 25
    # city: Delhi

enumerate() - Index bhi chahiye, value bhi

# Problem: Mujhe pata karna hai ki kaunsa fruit kis position pe hai
fruits = ["apple", "banana", "cherry"]

# Bina enumerate ke - kaam chalega but ugly hai
i = 0
for fruit in fruits:
    print(f"{i}: {fruit}")
    i += 1

# enumerate ke saath - clean aur Pythonic
for index, fruit in enumerate(fruits):
    print(f"{index}: {fruit}")
# 0: apple
# 1: banana
# 2: cherry

# Starting index change karna
for index, fruit in enumerate(fruits, start=1):
    print(f"{index}: {fruit}")
# 1: apple
# 2: banana
# 3: cherry

zip() - Do lists ko saath mein loop karna

names = ["Shweta", "Rahul", "Priya"]
scores = [85, 92, 78]

# zip dono lists ko pair kar deta hai
for name, score in zip(names, scores):
    print(f"{name} scored {score}")
# Shweta scored 85
# Rahul scored 92
# Priya scored 78

10 for Loop Examples (Simple to Medium)

# Example 1: 1 se 10 tak print karo
for i in range(1, 11):
    print(i)

# Example 2: List ka sum (total) nikalo
numbers = [10, 20, 30, 40]
total = 0
for num in numbers:
    total += num     # total = total + num
print(total)              # 100

# Example 3: Even numbers 1 se 20 tak
for i in range(1, 21):
    if i % 2 == 0:
        print(i)       # 2, 4, 6, 8, 10, 12, 14, 16, 18, 20

# Example 4: List mein sabse bada number dhundho
nums = [45, 12, 89, 34, 67]
biggest = nums[0]      # pehle element ko biggest maano
for num in nums:
    if num > biggest:
        biggest = num
print(f"Largest: {biggest}")  # 89

# Example 5: String ko ulta (reverse) karo
word = "hello"
reversed_word = ""
for char in word:
    reversed_word = char + reversed_word  # har character ko aage jodte jao
print(reversed_word)       # olleh

# Example 6: Count vowels in a string
text = "Hello World"
count = 0
for char in text.lower():
    if char in "aeiou":
        count += 1
print(f"Vowels: {count}")    # 3

# Example 7: Multiplication table
num = 7
for i in range(1, 11):
    print(f"{num} x {i} = {num * i}")

# Example 8: Remove duplicates from list (order maintain)
items = [1, 2, 2, 3, 4, 4, 5]
unique = []
for item in items:
    if item not in unique:
        unique.append(item)
print(unique)               # [1, 2, 3, 4, 5]

# Example 9: Create dictionary from two lists
keys = ["name", "age", "city"]
values = ["Shweta", 25, "Delhi"]
result = {}
for k, v in zip(keys, values):
    result[k] = v
print(result)               # {'name': 'Shweta', 'age': 25, 'city': 'Delhi'}

# Example 10: Flatten a 2D list
matrix = [[1, 2], [3, 4], [5, 6]]
flat = []
for row in matrix:
    for num in row:
        flat.append(num)
print(flat)                 # [1, 2, 3, 4, 5, 6]

while Loop

What is while loop?

while loop tab tak chalta rahega jab tak condition True hai. Jaise: "Jab tak barish ho rahi hai, ghar pe raho"

# Syntax:
# while condition:
#     kaam karo

# Example: 1 se 5 tak count
count = 1
while count <= 5:
    print(count)
    count += 1      # IMPORTANT: count badhana mat bhoolo!
# Output: 1, 2, 3, 4, 5

for vs while - Kab kya use karna?

for loopwhile loop
Jab pata ho kitni baar run karna haiJab pata na ho kitni baar run hoga
List, range, string mein loopCondition based loop
for i in range(10)while user_input != "quit"

Infinite Loop (Kabhi khatam na hone wala loop!)

# DANGER! Yeh kabhi nahi rukega - computer hang ho jaayega
# count = 1
# while count <= 5:
#     print(count)
# Kyunki count badh hi nahi raha, toh condition hamesha True rahegi!

# Fix: count += 1 add karo
count = 1
while count <= 5:
    print(count)
    count += 1      # yeh line bhoolna = infinite loop!

break and continue

# break = loop se bahar nikal jaao TURANT
for i in range(1, 11):
    if i == 5:
        break          # 5 pe rok do
    print(i)
# Output: 1, 2, 3, 4  (5 nahi aayega, loop ruk gaya)

# continue = is round ko skip karo, next round pe jaao
for i in range(1, 11):
    if i % 2 == 0:
        continue       # even numbers skip karo
    print(i)
# Output: 1, 3, 5, 7, 9 (sirf odd numbers)

while Loop Examples

# Example 1: User input lena jab tak "quit" na bole
# (Concept samjho, run karne ki zaroorat nahi)
user_input = ""
while user_input != "quit":
    user_input = input("Enter something (quit to exit): ")
    print(f"You said: {user_input}")

# Example 2: Guess the number game
secret = 7
guess = 0
attempts = 0
while guess != secret:
    guess = int(input("Guess a number (1-10): "))
    attempts += 1
    if guess < secret:
        print("Too low!")
    elif guess > secret:
        print("Too high!")
print(f"Correct! Took {attempts} attempts")

# Example 3: Sum of digits of a number
num = 12345
digit_sum = 0
while num > 0:
    digit_sum += num % 10     # last digit lo
    num = num // 10            # last digit hata do
print(f"Sum of digits: {digit_sum}")  # 15 (1+2+3+4+5)

# Example 4: Reverse a number
num = 1234
rev = 0
while num > 0:
    rev = rev * 10 + num % 10
    num = num // 10
print(f"Reversed: {rev}")     # 4321

# Example 5: Count down timer
timer = 10
while timer > 0:
    print(f"Time left: {timer}")
    timer -= 1
print("Time's up!")

Nested Loops (Loop ke andar Loop)

What is a Nested Loop?

Nested loop matlab ek loop ke andar doosra loop. Real life example: Ek building mein 3 floors hain, har floor pe 4 rooms hain. Tujhe har room mein jaana hai.

# Outer loop = floors, Inner loop = rooms
for floor in range(1, 4):          # 3 floors
    for room in range(1, 5):       # 4 rooms per floor
        print(f"Floor {floor}, Room {room}")

# Output:
# Floor 1, Room 1
# Floor 1, Room 2
# Floor 1, Room 3
# Floor 1, Room 4
# Floor 2, Room 1
# ... (total 12 combinations)

Step-by-Step Trace (Exactly kaise chalta hai)

# Trace karte hain: 2 rows, 3 columns
for i in range(1, 3):        # i = 1, 2
    for j in range(1, 4):    # j = 1, 2, 3
        print(f"({i},{j})", end=" ")
    print()  # new line
Stepi (outer)j (inner)Prints
111(1,1)
212(1,2)
313(1,3) + new line
421(2,1)
522(2,2)
623(2,3) + new line

Pattern Printing Examples

# Pattern 1: Right Triangle (stars)
# *
# * *
# * * *
# * * * *
for i in range(1, 5):           # rows: 1 to 4
    for j in range(i):          # columns: 0 to i-1 (i stars print hote hain)
        print("* ", end="")
    print()                       # new line

# Pattern 2: Square of numbers
# 1 2 3
# 4 5 6
# 7 8 9
num = 1
for i in range(3):
    for j in range(3):
        print(num, end=" ")
        num += 1
    print()

# Pattern 3: Pyramid
#     *
#    ***
#   *****
#  *******
n = 4
for i in range(1, n + 1):
    print(" " * (n - i), end="")       # spaces pehle
    print("*" * (2 * i - 1))             # stars

# Pattern 4: Inverted Triangle
# * * * * *
# * * * *
# * * *
# * *
# *
for i in range(5, 0, -1):
    for j in range(i):
        print("* ", end="")
    print()

# Pattern 5: Diamond
n = 4
# Upper half
for i in range(1, n + 1):
    print(" " * (n - i) + "*" * (2 * i - 1))
# Lower half
for i in range(n - 1, 0, -1):
    print(" " * (n - i) + "*" * (2 * i - 1))

List Comprehension

What is List Comprehension?

List comprehension ek shortcut hai list banane ka. Jo kaam 4 lines mein hota hai, woh 1 line mein ho jaata hai.

# Normal way (4 lines)
squares = []
for i in range(1, 6):
    squares.append(i ** 2)
print(squares)           # [1, 4, 9, 16, 25]

# List Comprehension way (1 line!)
squares = [i ** 2 for i in range(1, 6)]
print(squares)           # [1, 4, 9, 16, 25]

Syntax Breakdown

# [expression for item in iterable if condition]
#  ^what to do  ^loop part          ^filter (optional)

# Example 1: Even numbers 1 se 20 tak
evens = [i for i in range(1, 21) if i % 2 == 0]
print(evens)    # [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

# Example 2: Words ko uppercase mein karo
words = ["hello", "world", "python"]
upper_words = [w.upper() for w in words]
print(upper_words)  # ['HELLO', 'WORLD', 'PYTHON']

# Example 3: String ki length nikalo
names = ["Shweta", "Raj", "Priya"]
lengths = [len(n) for n in names]
print(lengths)    # [6, 3, 5]

# Example 4: if-else ke saath
nums = [1, 2, 3, 4, 5]
labels = ["even" if n % 2 == 0 else "odd" for n in nums]
print(labels)     # ['odd', 'even', 'odd', 'even', 'odd']

# Example 5: Nested list comprehension (2D se 1D)
matrix = [[1, 2], [3, 4], [5, 6]]
flat = [num for row in matrix for num in row]
print(flat)       # [1, 2, 3, 4, 5, 6]
Kab use karna, kab nahi

Simple operations ke liye list comprehension use karo. Agar logic bahut complicated ho jaa raha hai, toh normal for loop use karo. Readable code > clever code.

Section 3: Data Structures

Core Concepts

Lists

What is a List?

List ek ordered collection hai jisme tu kuch bhi store kar sakti hai. Yeh mutable hai (badal sakti hai).

# List banane ke tarike
fruits = ["apple", "banana", "cherry"]
numbers = [1, 2, 3, 4, 5]
mixed = [1, "hello", 3.14, True]   # mixed types bhi allowed
empty = []                              # khaali list

# List methods
fruits.append("mango")      # end mein add: ["apple", "banana", "cherry", "mango"]
fruits.insert(1, "grape")   # index 1 pe add: ["apple", "grape", "banana", ...]
fruits.remove("banana")     # "banana" hata do (first occurrence)
popped = fruits.pop()       # last item nikaal ke return karo
fruits.sort()                # alphabetical/ascending order
fruits.reverse()             # ulta kar do
print(len(fruits))           # kitne items hain

# List slicing (same as string slicing)
nums = [10, 20, 30, 40, 50]
print(nums[1:3])       # [20, 30]
print(nums[::-1])      # [50, 40, 30, 20, 10] (reverse)

# List unpacking
a, b, c = [1, 2, 3]    # a=1, b=2, c=3
first, *rest = [1, 2, 3, 4]  # first=1, rest=[2, 3, 4]

Shallow Copy vs Deep Copy (IMPORTANT!)

import copy

# Problem: Direct assignment copies REFERENCE, not value
a = [1, 2, [3, 4]]
b = a                 # b is pointing to same list as a
b[0] = 99
print(a)              # [99, 2, [3, 4]] - a bhi badal gaya!

# Shallow copy: outer list copy hoti hai, inner objects shared
a = [1, 2, [3, 4]]
b = a.copy()           # ya list(a) ya a[:]
b[0] = 99
print(a)              # [1, 2, [3, 4]] - a safe hai!
b[2][0] = 999
print(a)              # [1, 2, [999, 4]] - inner list shared hai!

# Deep copy: EVERYTHING separately copy hota hai
a = [1, 2, [3, 4]]
b = copy.deepcopy(a)
b[2][0] = 999
print(a)              # [1, 2, [3, 4]] - completely safe!

Dictionaries

# Dictionary = key:value pairs (jaise phone book - naam:number)
student = {
    "name": "Shweta",
    "age": 25,
    "marks": [85, 90, 78]
}

# Access values
print(student["name"])           # Shweta
print(student.get("name"))       # Shweta (safe way)
print(student.get("phone", "N/A"))  # N/A (default if key not found)

# Add / update
student["city"] = "Delhi"       # new key add
student["age"] = 26              # update existing

# Important methods
print(student.keys())     # dict_keys(['name', 'age', 'marks', 'city'])
print(student.values())   # dict_values(['Shweta', 26, [85, 90, 78], 'Delhi'])
print(student.items())    # key-value pairs as tuples

# Dictionary comprehension
squares = {i: i**2 for i in range(1, 6)}
print(squares)  # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

# Nested dictionary
school = {
    "class_10": {"students": 40, "teacher": "Mrs. Sharma"},
    "class_11": {"students": 35, "teacher": "Mr. Verma"}
}
print(school["class_10"]["teacher"])  # Mrs. Sharma

# defaultdict (from collections) - missing key pe default value
from collections import defaultdict
word_count = defaultdict(int)   # default value = 0
for word in ["a", "b", "a", "c", "a"]:
    word_count[word] += 1
print(dict(word_count))   # {'a': 3, 'b': 1, 'c': 1}

Tuples & Sets

# TUPLE - Immutable list (badal nahi sakti)
coords = (10, 20)
rgb = (255, 128, 0)
# coords[0] = 30   # ERROR! Cannot change tuple

# Tuple unpacking
x, y = coords              # x=10, y=20

# When to use tuple vs list?
# Tuple: jab data fix hai (coordinates, RGB color, database row)
# List: jab data change hota rahega (shopping cart, to-do list)

# ──────────────────────────────────────────

# SET - Unique values, unordered (koi duplicate nahi)
fruits = {"apple", "banana", "apple", "cherry"}
print(fruits)    # {'apple', 'banana', 'cherry'} - duplicate gaya!

# Set operations
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

print(a | b)     # {1, 2, 3, 4, 5, 6}  Union (sab mila do)
print(a & b)     # {3, 4}              Intersection (common)
print(a - b)     # {1, 2}              Difference (a mein hai, b mein nahi)
print(a ^ b)     # {1, 2, 5, 6}        Symmetric diff (dono mein se uncommon)

# frozenset - immutable set (hashable, dict key ban sakta hai)
fs = frozenset([1, 2, 3])
# fs.add(4)  # ERROR! Cannot change frozenset
FeatureListTupleSetDict
Ordered?YesYesNoYes (3.7+)
Mutable?YesNoYesYes
Duplicates?YesYesNoKeys: No
Indexing?YesYesNoBy key
Syntax[](){}{k:v}

Section 4: Functions

Building Blocks

Function Basics

# Function kya hai? Ek reusable block of code.
# Jaise recipe: ek baar likh do, baar baar use karo

# Define karna (banane)
def greet(name):
    return f"Hello, {name}!"

# Call karna (use karna)
message = greet("Shweta")
print(message)    # Hello, Shweta!

# Parameters vs Arguments
# Parameter = function define karte waqt (name)
# Argument = function call karte waqt ("Shweta")

# Default parameters
def greet(name, greeting="Hello"):
    return f"{greeting}, {name}!"

print(greet("Shweta"))               # Hello, Shweta!
print(greet("Shweta", "Namaste"))    # Namaste, Shweta!

# Return statement
def add(a, b):
    return a + b    # value return karta hai

result = add(3, 5)
print(result)        # 8

# Multiple values return
def min_max(numbers):
    return min(numbers), max(numbers)

smallest, largest = min_max([3, 1, 7, 2])
print(smallest, largest)   # 1 7

*args and **kwargs

# *args = jitne bhi positional arguments bhejo, sab aa jaayenge (tuple mein)
def total(*args):
    print(type(args))   # <class 'tuple'>
    return sum(args)

print(total(1, 2, 3))        # 6
print(total(10, 20, 30, 40))  # 100

# **kwargs = jitne bhi keyword arguments bhejo (dictionary mein)
def introduce(**kwargs):
    print(type(kwargs))  # <class 'dict'>
    for key, value in kwargs.items():
        print(f"{key}: {value}")

introduce(name="Shweta", age=25, city="Delhi")
# name: Shweta
# age: 25
# city: Delhi

# Dono saath mein
def flex(*args, **kwargs):
    print(f"args: {args}")
    print(f"kwargs: {kwargs}")

flex(1, 2, name="Shweta")
# args: (1, 2)
# kwargs: {'name': 'Shweta'}

Lambda, map, filter, reduce

# Lambda = one-line anonymous function (bina naam ki function)
square = lambda x: x ** 2
print(square(5))       # 25

add = lambda a, b: a + b
print(add(3, 5))      # 8

# map() = har element pe function lagao
nums = [1, 2, 3, 4]
squares = list(map(lambda x: x**2, nums))
print(squares)         # [1, 4, 9, 16]

# filter() = condition ke basis pe filter karo
evens = list(filter(lambda x: x % 2 == 0, nums))
print(evens)           # [2, 4]

# reduce() = sab ko ek value mein reduce karo
from functools import reduce
total = reduce(lambda a, b: a + b, nums)
print(total)           # 10 (1+2+3+4)

Decorators & Generators

# DECORATOR = ek function jo doosri function ko modify kare
# Real-world: security guard (decorator) jo har visitor (function) ko check karta hai

def make_bold(func):
    def wrapper():
        return f"<b>{func()}</b>"
    return wrapper

@make_bold
def hello():
    return "Hello World"

print(hello())    # <b>Hello World</b>

# Practical example: timing decorator
import time

def timer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        print(f"{func.__name__} took {time.time() - start:.4f}s")
        return result
    return wrapper

# ──────────────────────────────────────────

# GENERATOR = lazy iterator (ek ek karke value deta hai, sab ek saath nahi)
# yield use karte hain return ki jagah

def count_up_to(n):
    i = 1
    while i <= n:
        yield i       # return like but pauses here
        i += 1

for num in count_up_to(5):
    print(num)      # 1, 2, 3, 4, 5

# Fayda: Memory save hoti hai (sab numbers ek saath store nahi hote)
# Generator expression (list comprehension jaisa but () mein)
gen = (x**2 for x in range(1000000))   # barely uses memory

Section 5: Exception Handling

Error Management
# Exception kya hai?
# Jab Python ko koi error milta hai, woh ek "exception" raise karta hai
# Agar handle nahi kiya, toh program crash ho jaata hai

# try-except: Error handle karna
try:
    result = 10 / 0
except ZeroDivisionError:
    print("Cannot divide by zero!")

# Multiple exceptions
try:
    num = int("abc")
except ValueError:
    print("Invalid number!")
except TypeError:
    print("Wrong type!")

# try-except-else-finally
try:
    num = int("42")
except ValueError:
    print("Invalid!")
else:
    print(f"Success! Number is {num}")   # jab koi error nahi aaya
finally:
    print("This ALWAYS runs!")            # chahe error aaye ya nahi

# Common exceptions
# ValueError    - wrong value (int("abc"))
# TypeError     - wrong type (1 + "hello")
# KeyError      - dict mein key nahi mili
# IndexError    - list mein index out of range
# FileNotFoundError - file nahi mili
# ZeroDivisionError - 0 se divide

# raise - khud exception raise karna
def set_age(age):
    if age < 0:
        raise ValueError("Age cannot be negative!")
    return age

# Custom exception banane
class InvalidPANError(Exception):
    pass

def validate_pan(pan):
    if len(pan) != 10:
        raise InvalidPANError(f"PAN must be 10 characters, got {len(pan)}")

Section 6: File Handling

I/O Operations
# File open karna - purana tarika (close karna padta hai)
f = open("data.txt", "r")    # r=read, w=write, a=append
content = f.read()
f.close()                       # MUST close!

# with statement - BEST way (auto-close hota hai)
with open("data.txt", "r") as f:
    content = f.read()          # poora file padh lo
# file automatically close ho gaya

# Read methods
with open("data.txt") as f:
    all_text = f.read()             # poora file ek string mein
    # f.readline()                   # ek line padho
    # f.readlines()                  # sab lines list mein

# Write to file
with open("output.txt", "w") as f:   # w = overwrite
    f.write("Hello World\n")
    f.write("Second line\n")

with open("output.txt", "a") as f:   # a = append (add at end)
    f.write("Third line\n")

# Read line by line (memory efficient for large files)
with open("data.txt") as f:
    for line in f:
        print(line.strip())          # strip() removes \n

# CSV file reading
import csv
with open("data.csv") as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)           # ['col1', 'col2', 'col3']

# JSON file reading
import json
with open("data.json") as f:
    data = json.load(f)        # JSON → Python dict/list

# JSON write
data = {"name": "Shweta", "age": 25}
with open("output.json", "w") as f:
    json.dump(data, f, indent=2)

Section 7: Coding Questions

Practice Problems

Question 1: PAN Card Validation using Regex

Problem Medium

PAN Card format: ABCDE1234F (5 uppercase letters + 4 digits + 1 uppercase letter, total 10 chars)

Write a function to validate if a given string is a valid PAN card number.

First: What is Regex? (Regex kya hai?)

Regex (Regular Expression) ek pattern matching language hai. Isse tu text mein patterns dhundh sakti hai. Jaise: "kya yeh email address valid hai?" ya "kya yeh phone number sahi format mein hai?"

PatternMeaningExample
[A-Z]Any uppercase letterA, B, Z
[a-z]Any lowercase lettera, b, z
[0-9]Any digit0, 5, 9
{5}Exactly 5 times[A-Z]{5} = 5 uppercase letters
^Start of string^A = starts with A
$End of stringZ$ = ends with Z
.Any charactera.c = abc, axc, a1c
+1 or more timesa+ = a, aa, aaa
*0 or more timesa* = "", a, aa
\dAny digit (same as [0-9])1, 5
\wAny word charactera, Z, 5, _

PAN Pattern Breakdown

^[A-Z]{5}[0-9]{4}[A-Z]$

^         = String ki shuruaat se match karo
[A-Z]{5}  = 5 uppercase letters (ABCDE)
[0-9]{4}  = 4 digits (1234)
[A-Z]     = 1 uppercase letter (F)
$         = String ka end yahi hona chahiye

Full Code

import re

def validate_pan(pan):
    """
    PAN card validate karo.
    Format: ABCDE1234F (5 letters + 4 digits + 1 letter)
    Returns: True if valid, False otherwise
    """
    # Step 1: Input ko clean karo (spaces hatao, uppercase karo)
    pan = pan.strip().upper()

    # Step 2: Length check
    if len(pan) != 10:
        return False

    # Step 3: Regex pattern
    pattern = r"^[A-Z]{5}[0-9]{4}[A-Z]$"

    # Step 4: Match karo
    if re.match(pattern, pan):
        return True
    return False


# Test cases
test_pans = [
    ("ABCDE1234F", True),    # Valid
    ("BNZAA2318J", True),    # Valid
    ("abcde1234f", True),    # Valid (lowercase → upper kiya)
    ("  ABCDE1234F  ", True), # Valid (spaces → strip kiya)
    ("ABCDE123F",  False),   # Invalid (9 chars only)
    ("12345ABCDE", False),   # Invalid (wrong format)
    ("ABCDE12345", False),   # Invalid (ends with digit)
    ("",           False),   # Invalid (empty)
]

for pan, expected in test_pans:
    result = validate_pan(pan)
    status = "PASS" if result == expected else "FAIL"
    print(f"[{status}] PAN: '{pan}' → {result}")
[PASS] PAN: 'ABCDE1234F' → True
[PASS] PAN: 'BNZAA2318J' → True
[PASS] PAN: 'abcde1234f' → True
[PASS] PAN: '  ABCDE1234F  ' → True
[PASS] PAN: 'ABCDE123F' → False
[PASS] PAN: '12345ABCDE' → False
[PASS] PAN: 'ABCDE12345' → False
[PASS] PAN: '' → False

Time: O(n) Space: O(1)

re.match vs re.search vs re.findall

re.match() - sirf string ke start se check karta hai
re.search() - poori string mein kahin bhi dhundhta hai
re.findall() - sab matches ki list return karta hai

Question 2: Flatten Nested List

Problem Hard

Given: [[1, 2, [3, 4]], [5, [6, [7, 8]]], 9]

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

What is a Nested List?

Nested list matlab list ke andar list. Jaise Russian dolls - ek doll ke andar doosri doll.

# Simple list (1 level)
[1, 2, 3]

# Nested list (multiple levels)
[1, [2, 3], [4, [5, 6]]]
# Level 0: [1, [...], [...]]
# Level 1: [2, 3] and [4, [...]]
# Level 2: [5, 6]

Why Simple Loop Doesn't Work?

nested = [1, [2, [3]]]
flat = []
for item in nested:
    flat.append(item)
print(flat)   # [1, [2, [3]]] - nested list waise ka waisa!
# Kyunki loop sirf outer level tak jaata hai

Method 1: Recursion (IMPORTANT - samjho isko!)

Recursion kya hai?

Recursion matlab ek function jo khud ko call kare. Jaise tu mirror ke saamne mirror rakhe - andar reflection dikhe, uske andar aur reflection. Lekin ek point pe ruk jaaye (base case).

def flatten(nested_list):
    """Nested list ko flat karo using recursion"""
    result = []

    for item in nested_list:
        if isinstance(item, list):
            # Agar item ek list hai, toh usko bhi flatten karo (RECURSION)
            result.extend(flatten(item))
        else:
            # Agar item normal value hai, toh seedha add karo
            result.append(item)

    return result


# Test
nested = [[1, 2, [3, 4]], [5, [6, [7, 8]]], 9]
print(flatten(nested))   # [1, 2, 3, 4, 5, 6, 7, 8, 9]

Step-by-Step Trace (Call Stack)

flatten([[1, 2, [3, 4]], [5, [6, [7, 8]]], 9])
  |
  ├─ item = [1, 2, [3, 4]] → is list → flatten([1, 2, [3, 4]])
  |    ├─ item = 1 → not list → append(1)
  |    ├─ item = 2 → not list → append(2)
  |    └─ item = [3, 4] → is list → flatten([3, 4])
  |         ├─ item = 3 → not list → append(3)
  |         └─ item = 4 → not list → append(4)
  |         return [3, 4]
  |    return [1, 2, 3, 4]
  |
  ├─ item = [5, [6, [7, 8]]] → is list → flatten([5, [6, [7, 8]]])
  |    ├─ item = 5 → not list → append(5)
  |    └─ item = [6, [7, 8]] → is list → flatten([6, [7, 8]])
  |         ├─ item = 6 → not list → append(6)
  |         └─ item = [7, 8] → is list → flatten([7, 8])
  |              ├─ item = 7 → append(7)
  |              └─ item = 8 → append(8)
  |              return [7, 8]
  |         return [6, 7, 8]
  |    return [5, 6, 7, 8]
  |
  └─ item = 9 → not list → append(9)

Final result: [1, 2, 3, 4, 5, 6, 7, 8, 9]

Method 2: Iterative (Using while loop + stack)

def flatten_iterative(nested_list):
    stack = list(nested_list)  # copy banao
    result = []

    while stack:
        item = stack.pop(0)    # pehla item nikalo
        if isinstance(item, list):
            stack = item + stack  # list ke items ko stack mein daalo
        else:
            result.append(item)

    return result

print(flatten_iterative([[1, 2, [3]], 4]))  # [1, 2, 3, 4]

Method 3: Using generator (elegant)

def flatten_gen(nested):
    for item in nested:
        if isinstance(item, list):
            yield from flatten_gen(item)
        else:
            yield item

print(list(flatten_gen([[1, [2, [3]]], 4])))  # [1, 2, 3, 4]

Edge Cases

print(flatten([]))                  # [] (empty list)
print(flatten([1, 2, 3]))           # [1, 2, 3] (already flat)
print(flatten([[[[[1]]]]]))        # [1] (deeply nested)
print(flatten([[], [1], [], [2]])) # [1, 2] (empty sublists)

Time: O(n) where n = total elements Space: O(d) where d = max depth

Question 3: Reverse a String (without [::-1])

Problem Easy

# Method 1: Loop se
def reverse_string(s):
    result = ""
    for char in s:
        result = char + result   # har char ko pehle jodo
    return result

# Dry run: s = "hello"
# char='h' → result="h"
# char='e' → result="eh"
# char='l' → result="leh"
# char='l' → result="lleh"
# char='o' → result="olleh"

# Method 2: Two pointers
def reverse_string_2(s):
    chars = list(s)
    left, right = 0, len(chars) - 1
    while left < right:
        chars[left], chars[right] = chars[right], chars[left]
        left += 1
        right -= 1
    return "".join(chars)

# Method 3: Using reversed()
def reverse_string_3(s):
    return "".join(reversed(s))

print(reverse_string("hello"))    # olleh
print(reverse_string("Python"))   # nohtyP

Time: O(n) Space: O(n)

Question 4: Check Palindrome

Problem Easy

Palindrome = ulta padhne pe bhi same rahe (madam, racecar, 121)

def is_palindrome(s):
    s = s.lower().replace(" ", "")   # lowercase + spaces remove
    left, right = 0, len(s) - 1

    while left < right:
        if s[left] != s[right]:
            return False
        left += 1
        right -= 1
    return True

# Dry run: s = "madam"
# left=0 right=4: 'm'=='m' ✓
# left=1 right=3: 'a'=='a' ✓
# left=2 right=2: done (left not < right)
# Return True

print(is_palindrome("madam"))       # True
print(is_palindrome("Race Car"))    # True
print(is_palindrome("hello"))       # False

Time: O(n) Space: O(1)

Question 5: Second Largest Number

Problem Easy

def second_largest(nums):
    if len(nums) < 2:
        return None

    first = second = float('-inf')   # sabse chhota possible number

    for num in nums:
        if num > first:
            second = first     # purana first ab second ban gaya
            first = num        # naya number sabse bada
        elif num > second and num != first:
            second = num

    return second if second != float('-inf') else None

# Dry run: nums = [10, 5, 20, 15]
# first=-inf, second=-inf
# num=10: 10 > -inf → second=-inf, first=10
# num=5:  5 < 10, 5 > -inf → second=5
# num=20: 20 > 10 → second=10, first=20
# num=15: 15 < 20, 15 > 10 → second=15
# Return 15

print(second_largest([10, 5, 20, 15]))   # 15
print(second_largest([5, 5, 5]))        # None (sab same)

Time: O(n) - ek baar loop Space: O(1)

Question 6: Character Frequency

Problem Easy

def char_frequency(s):
    freq = {}
    for char in s:
        freq[char] = freq.get(char, 0) + 1
    return freq

print(char_frequency("hello"))
# {'h': 1, 'e': 1, 'l': 2, 'o': 1}

# Method 2: Using Counter (shortest)
from collections import Counter
print(Counter("hello"))
# Counter({'l': 2, 'h': 1, 'e': 1, 'o': 1})

Time: O(n) Space: O(k) where k = unique characters

Question 7: Remove Duplicates (Maintain Order)

Problem Easy

def remove_duplicates(lst):
    seen = set()
    result = []
    for item in lst:
        if item not in seen:
            seen.add(item)
            result.append(item)
    return result

print(remove_duplicates([3, 1, 2, 3, 4, 1, 5]))
# [3, 1, 2, 4, 5] (order maintained, duplicates gone)

# Method 2: dict.fromkeys (order maintained in Python 3.7+)
print(list(dict.fromkeys([3, 1, 2, 3, 4, 1])))
# [3, 1, 2, 4]

Time: O(n) Space: O(n)

Question 8: FizzBuzz

Problem Easy

Print 1-100. Multiples of 3: "Fizz", 5: "Buzz", both: "FizzBuzz"

def fizzbuzz(n):
    for i in range(1, n + 1):
        if i % 15 == 0:       # 3 aur 5 dono se divisible (15 se check karo)
            print("FizzBuzz")
        elif i % 3 == 0:
            print("Fizz")
        elif i % 5 == 0:
            print("Buzz")
        else:
            print(i)

fizzbuzz(20)
# 1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz, 16, ...
Important

i % 15 == 0 ki check PEHLE honi chahiye i % 3 aur i % 5 se, warna 15 pe "Fizz" print hoga "FizzBuzz" ki jagah.

Time: O(n) Space: O(1)

Question 9: Two Sum

Problem Medium

Given list and target, find two numbers that add up to target. Return their indices.

def two_sum(nums, target):
    seen = {}   # {number: index}

    for i, num in enumerate(nums):
        complement = target - num   # kya chahiye target banane ke liye?
        if complement in seen:
            return [seen[complement], i]
        seen[num] = i

    return []

# Dry run: nums=[2, 7, 11, 15], target=9
# i=0, num=2: complement=7, seen={} → 7 not in seen → seen={2:0}
# i=1, num=7: complement=2, seen={2:0} → 2 IN seen! → return [0, 1]

print(two_sum([2, 7, 11, 15], 9))   # [0, 1]
print(two_sum([3, 2, 4], 6))        # [1, 2]

Time: O(n) Space: O(n)

Question 10: Anagram Check

Problem Easy

Anagram = same letters, different order. "listen" and "silent" are anagrams.

def is_anagram(s1, s2):
    # Method 1: Sort and compare
    return sorted(s1.lower()) == sorted(s2.lower())

def is_anagram_v2(s1, s2):
    # Method 2: Counter (better)
    from collections import Counter
    return Counter(s1.lower()) == Counter(s2.lower())

print(is_anagram("listen", "silent"))   # True
print(is_anagram("hello", "world"))    # False

Method 1 Time: O(n log n) Method 2 Time: O(n)

Question 11: Common Elements

Problem Easy

def common_elements(list1, list2):
    # Method 1: Set intersection (fastest)
    return list(set(list1) & set(list2))

def common_elements_v2(list1, list2):
    # Method 2: List comprehension
    return [x for x in list1 if x in list2]

print(common_elements([1, 2, 3, 4], [3, 4, 5, 6]))   # [3, 4]

Method 1: O(n+m) Method 2: O(n*m)

Question 12: Fibonacci Series

Problem Medium

Fibonacci: 0, 1, 1, 2, 3, 5, 8, 13, 21... (har number pichle do ka sum hai)

# Method 1: Iterative (BEST for interviews)
def fibonacci_iter(n):
    if n <= 0:
        return []
    if n == 1:
        return [0]

    fib = [0, 1]
    for i in range(2, n):
        fib.append(fib[-1] + fib[-2])  # last two ka sum
    return fib

print(fibonacci_iter(10))
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

# Method 2: Recursive
def fibonacci_rec(n):
    if n <= 0:
        return 0
    if n == 1:
        return 1
    return fibonacci_rec(n - 1) + fibonacci_rec(n - 2)

# Note: Recursive bahut slow hai (O(2^n)), iterative use karo

# Method 3: Generator (memory efficient)
def fib_generator():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

gen = fib_generator()
for _ in range(10):
    print(next(gen), end=" ")  # 0 1 1 2 3 5 8 13 21 34

Iterative: O(n) time, O(n) space Recursive: O(2^n) time (very slow!)

Section 8: General Python Interview Q&A

30 Questions
1. What is Python? Interpreted vs Compiled?

Python ek high-level, interpreted, general-purpose programming language hai.

Interpreted: Code line by line execute hota hai (jaise Python, JavaScript). Error aata hai toh us line pe ruk jaata hai.

Compiled: Poora code pehle machine code mein convert hota hai, phir execute (jaise C, C++, Java). Sab errors pehle milte hain.

Python technically both hai - pehle bytecode mein compile hota hai (.pyc), phir PVM (Python Virtual Machine) interpret karta hai.

2. What is PEP 8?

PEP 8 Python ka official style guide hai. Yeh batata hai ki Python code kaise likhna chahiye taaki sab consistent dikhe:

  • 4 spaces for indentation (tab nahi)
  • Line max 79 characters
  • Functions/variables: snake_case, Classes: CamelCase
  • 2 blank lines between functions
3. What is GIL (Global Interpreter Lock)?

GIL ek lock hai jo Python interpreter mein hota hai. Yeh ensure karta hai ki ek time pe sirf EK thread Python bytecode execute kar sake, chahe tere paas multiple CPU cores ho. Isliye Python ka multi-threading CPU-bound tasks ke liye slow hai. Solution: multiprocessing module use karo ya asyncio for I/O-bound tasks.

4. Deep Copy vs Shallow Copy?

Shallow copy: Naya object banta hai, lekin nested objects same reference share karte hain. a.copy() ya list(a)

Deep copy: Naya object aur saare nested objects bhi naye bante hain. copy.deepcopy(a)

Simple rule: Nested data ho toh deepcopy, flat data ho toh shallow copy kaafi hai.

5. List vs Tuple vs Set vs Dictionary?

List: Ordered, mutable, duplicates OK. [1, 2, 3]

Tuple: Ordered, immutable, duplicates OK. (1, 2, 3)

Set: Unordered, mutable, NO duplicates. {1, 2, 3}

Dict: Key-value pairs, ordered (3.7+), keys unique. {"a": 1}

6. What is __init__?

__init__ ek constructor hai. Jab bhi class ka naya object banate hain, yeh method automatically call hota hai. Isme hum object ki initial values set karte hain.

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

s = Student("Shweta", 25)  # __init__ automatically call hua
7. What is self?

self current object ko refer karta hai. Jaise "main" (mein). Class ke methods mein hamesha pehla parameter self hota hai. Isse hum object ke attributes aur methods access karte hain.

8. Mutable vs Immutable?

Mutable: Value change kar sakti hai creation ke baad. list, dict, set

Immutable: Value change NAHI kar sakti. int, float, str, tuple, frozenset

Interview trick: "Kya string mutable hai?" - NAHI. s[0] = 'x' error dega.

9. What are Decorators?

Decorator ek function hai jo doosri function ka behavior modify karta hai bina uska code change kiye. @decorator_name syntax se use hota hai. Common uses: logging, authentication check, timing.

10. What is Lambda?

Lambda ek anonymous (bina naam ki) function hai jo ek line mein define hoti hai. lambda arguments: expression. Useful for short, throwaway functions (map, filter, sort ke saath).

11. is vs == difference?

== checks value equality (kya values same hain?)

is checks identity (kya same object hai memory mein?)

[1,2] == [1,2] is True, but [1,2] is [1,2] is False (alag objects hain).

12. What are *args and **kwargs?

*args = variable number of positional arguments (tuple mein aate hain)

**kwargs = variable number of keyword arguments (dict mein aate hain)

Order: def func(regular, *args, **kwargs)

13. What is List Comprehension?

List banane ka ek short, Pythonic way. [expression for item in iterable if condition]. Ek for loop + append ko ek line mein likh deta hai.

14. What is a Generator?

Generator ek function hai jo yield use karta hai. Yeh values ek ek karke deta hai (lazy evaluation), sab ek saath memory mein nahi rakhta. Large data ke liye bahut memory efficient. yield function ko pause karta hai, next() se resume hota hai.

15. append vs extend?

append() ek item add karta hai: [1,2].append([3,4]) = [1, 2, [3, 4]]

extend() iterable ke items add karta hai: [1,2].extend([3,4]) = [1, 2, 3, 4]

16. How is Memory Managed in Python?

Python ka apna private heap hai. Memory manager automatically handle karta hai. Reference counting + garbage collection se unused objects free hote hain. Small integers (-5 to 256) aur short strings cached rehte hain.

17. What is Garbage Collection?

Garbage Collection automatically un objects ko memory se free karta hai jinko koi reference nahi raha. Python mein primarily reference counting use hota hai (jab count 0 ho, free kar do) + cyclic garbage collector (circular references ke liye).

18. What is Monkey Patching?

Runtime pe kisi class ya module ka behavior change karna. Example: testing mein API call ko mock karna. Dynamic nature of Python allows this, but production mein avoid karo.

19. What are Python Namespaces?

Namespace ek mapping hai name se object tak. Python mein 4 namespaces hain (LEGB rule): Local (function ke andar) > Enclosing (outer function) > Global (module level) > Built-in (Python built-ins like print, len).

20. Module vs Package?

Module: Ek single .py file. import math

Package: Ek folder jo modules contain karta hai + __init__.py file. import mypackage.mymodule

21. What is virtualenv?

Virtual environment ek isolated Python environment hai. Har project ke apne packages ho sakte hain bina doosre projects ko affect kiye. python -m venv myenv se banao, source myenv/bin/activate se activate karo.

22. What is pip?

pip Python ka package manager hai. pip install requests se packages install karo. pip freeze se installed packages dekho. requirements.txt mein sab packages list karo.

23. What is __name__ == "__main__"?

Jab Python file directly run karo toh __name__ = "__main__". Jab import karo toh __name__ = module ka naam. Yeh check ensure karta hai ki kuch code sirf tab chale jab file directly run ho, import hone pe nahi.

if __name__ == "__main__":
    main()  # sirf direct run pe chalega
24. range vs xrange?

Python 2 mein: range() poori list banata tha (memory use), xrange() lazy iterator tha.

Python 3 mein: range() already lazy hai (purana xrange jaisa). xrange exist nahi karta.

25. How to Handle Exceptions?

try block mein risky code, except mein error handle, else jab koi error nahi, finally hamesha chale. Specific exceptions catch karo, bare except avoid karo.

26. What is the with statement?

with statement context manager ke liye use hota hai. Yeh automatically resource cleanup karta hai (file close, connection close). Best for file handling.

with open("file.txt") as f:
    data = f.read()
# file automatically close ho gaya, chahe error aaye ya na aaye
27. What are Dunder Methods?

Dunder = Double UNDERscore. Special methods like __init__, __str__, __len__, __add__. Yeh Python ka "magic" hai - operators aur built-in functions customize kar sakti hai.

class Point:
    def __init__(self, x, y): self.x, self.y = x, y
    def __str__(self): return f"({self.x}, {self.y})"
    def __add__(self, other): return Point(self.x+other.x, self.y+other.y)
28. What is Duck Typing?

"If it walks like a duck and quacks like a duck, it's a duck." Python mein type matter nahi karta, behavior matter karta hai. Agar object mein required method hai, toh kaam chal jaayega chahe type kuch bhi ho.

29. Process vs Thread?

Process: Independent program, apni memory, heavy. multiprocessing module.

Thread: Process ke andar, shared memory, lightweight. threading module.

Python mein GIL ki wajah se threads CPU-bound tasks ke liye slow hain. I/O-bound ke liye threads OK, CPU-bound ke liye processes use karo.

30. What is async/await?

Asynchronous programming - jab I/O wait ho (network call, file read), toh us time doosra kaam karo instead of waiting. async def se async function banao, await se async call karo. asyncio module use hota hai. Performance bahut improve hoti hai jab bahut saare I/O operations hain.

import asyncio

async def fetch_data():
    print("Fetching...")
    await asyncio.sleep(1)   # 1 sec wait, but non-blocking
    return "Data ready"

Section 9: Quick Revision Cards

Cheat Sheet
Data Types

int float str bool list tuple dict set
Mutable: list, dict, set
Immutable: int, float, str, tuple

String Methods

.upper() .lower() .strip() .split() .join() .replace() .find() .startswith() .endswith()

List Methods

.append() .insert() .remove() .pop() .sort() .reverse() .extend() .index() .count()

Dict Methods

.get() .keys() .values() .items() .update() .pop() .setdefault()

Loop Patterns

for i in range(n)
for item in list
for i, item in enumerate(list)
for a, b in zip(x, y)
while condition

List Comprehension

[x for x in list]
[x for x in list if cond]
[x if cond else y for x in list]
{k:v for k,v in dict.items()}

Functions

def func(a, b=10)
*args = tuple of extra args
**kwargs = dict of named args
lambda x: x*2
map() filter() reduce()

Exception Handling

try → except → else → finally
Common: ValueError, TypeError, KeyError, IndexError
raise to throw errors

File Handling

with open("f.txt","r") as f:
f.read() f.readline() f.readlines()
f.write()
Modes: r, w, a, r+

Important Built-ins

len() type() print() input() range() enumerate() zip() map() filter() sorted() reversed() isinstance() sum() min() max()

Common Imports

from collections import Counter, defaultdict
import re (regex)
import json
import csv
from functools import reduce
import copy (deepcopy)

Complexity Basics

O(1) - constant (dict lookup)
O(n) - linear (one loop)
O(n^2) - nested loops
O(log n) - binary search
O(n log n) - sorting

Common Coding Patterns

# Pattern 1: Frequency Count
from collections import Counter
freq = Counter(items)

# Pattern 2: Two Pointer
left, right = 0, len(arr) - 1
while left < right: ...

# Pattern 3: Hash Map for O(1) lookup
seen = {}   # or set()
if item in seen: ...

# Pattern 4: Sliding Window
for i in range(len(arr) - k + 1):
    window = arr[i:i+k]

# Pattern 5: Swap without temp
a, b = b, a

# Pattern 6: Default dict for grouping
from collections import defaultdict
groups = defaultdict(list)
for item in items:
    groups[item.category].append(item)

Final Tips for Interview

Best of luck for the interview! Tu kar legi! 💪