Introduction to Programming &
Python
Comprehensive End-Semester Study Guide
Covers: All Units — Theory, Concepts, Code Examples & Exam Tips
UNIT 1: Introduction to Programming
1.1 Types of Programming Languages
Low-Level Languages
Low-level languages are closer to the hardware (machine) and provide little or no abstraction from the
computer's instruction set architecture. They are fast and efficient but difficult to write, read, and debug.
• Machine Language (1st Generation): Binary code (0s and 1s) directly executed by CPU. E.g.,
10110000 01100001
• Assembly Language (2nd Generation): Uses mnemonics like MOV, ADD, SUB. Needs an
assembler to convert to machine code. Still hardware-specific.
📝 Low-level languages offer maximum performance and control but are tedious to program and
not portable across different CPU architectures.
High-Level Languages
High-level languages are closer to human language (English-like syntax) and abstract away hardware
details. They are portable, easier to learn, and more productive.
• Examples: Python, Java, C++, C#, JavaScript, Ruby, Go, Swift
• Require translation to machine code via a compiler or interpreter
💡 High-level languages trade raw speed for developer productivity and portability — a key
tradeoff to remember.
Feature Low-Level
Comparison Summary:
Low-Level Languages High-Level Languages
Close to hardware Close to human language
Difficult to write/read Easy to write/read
Machine dependent (not portable) Platform independent (portable)
Faster execution Slightly slower (translation overhead)
Examples: Machine code, Assembly Examples: Python, Java, C++
1.2 Compiled vs. Interpreted Languages
Compiled Languages
In compiled languages, the entire source code is translated to machine code BEFORE execution by a
program called a compiler. The output is a standalone executable file (.exe, .out).
• Process: Source Code → Compiler → Machine Code / Executable → Run
• Advantages: Faster execution, errors caught at compile time, code is protected
• Disadvantages: Platform dependent executables, slower development cycle
• Examples: C, C++, Go, Rust, Fortran, Pascal
// C example — must compile first #include <stdio.h> int main()
{ printf("Hello"); return 0; } // gcc hello.c -o hello → then run ./hello
Interpreted Languages
In interpreted languages, source code is executed line-by-line by a program called an interpreter at
runtime. No separate compilation step is needed.
• Process: Source Code → Interpreter reads & executes line by line
• Advantages: Platform independent, rapid development, easier debugging
• Disadvantages: Slower execution, requires interpreter on target machine
• Examples: Python, Ruby, JavaScript (traditionally), PHP, Perl
# Python — interpreted directly print('Hello World') # runs immediately with:
python [Link]
Hybrid (Bytecode) Languages
Some languages compile to an intermediate bytecode which is then interpreted by a virtual machine.
Java and Python both use this approach.
• Java: .java → javac → .class (bytecode) → JVM executes
• Python (CPython): .py → compile → .pyc (bytecode) → Python VM executes
💡 Python is often called 'interpreted' but technically CPython compiles to bytecode first. This
gives portability AND reasonable speed.
Compiled Interpreted
Translated all at once Translated line by line
Faster execution Slower execution
Platform-specific binaries Platform-independent
Errors found at compile time Errors found at runtime
C, C++, Go, Rust Python, Ruby, JavaScript
1.3 Programming Paradigms
1.3.1 Procedural Programming
Procedural programming organizes code as a sequence of instructions (procedures/functions) that
execute step by step. It uses top-down design and emphasizes HOW to solve a problem.
• Code is broken into functions/procedures
• Data and functions are separate
• Control flow: sequential, selection (if/else), iteration (loops)
• Examples: C, Pascal, early BASIC
# Procedural style def calculate_area(length, width): return length * width
result = calculate_area(5, 3) print(result) # 15
📝 Python supports procedural programming — writing functions without classes is procedural
style.
1.3.2 Object-Oriented Programming (OOP)
OOP organizes code around objects — entities that combine data (attributes) and behavior (methods).
It models real-world entities. The four pillars of OOP are:
• Encapsulation: Bundling data and methods together; hiding internal details
• Inheritance: A class can inherit properties/methods from a parent class
• Polymorphism: Same interface, different implementations (method overriding)
• Abstraction: Hiding complex implementation, showing only essentials
• Examples: Python, Java, C++, C#, Ruby
# OOP style class Animal: def speak(self): pass class Dog(Animal):
def speak(self): return 'Woof!'
1.3.3 Functional Programming
Functional programming treats computation as the evaluation of mathematical functions. It avoids
changing state and mutable data. Key concepts include:
• Pure functions: Given the same input, always return the same output; no side effects
• Immutability: Data is not modified after creation
• Higher-order functions: Functions that take or return other functions
• First-class functions: Functions treated as values
• Examples: Haskell, Lisp; Python, JavaScript support functional features
# Functional style in Python numbers = [1, 2, 3, 4, 5] squares = list(map(lambda
x: x**2, numbers)) evens = list(filter(lambda x: x % 2 == 0, numbers))
1.3.4 Event-Driven Programming
Event-driven programming is a paradigm where the flow of the program is determined by events —
user actions (clicks, key presses), messages from other programs, or system-generated events.
• Program waits in an event loop
• When an event occurs, a handler function (callback) is triggered
• Used heavily in: GUIs, web applications, mobile apps, game development
• Examples: JavaScript (browser events), Tkinter (Python GUI), [Link]
# Simple event concept (Tkinter) import tkinter as tk root = [Link]() btn =
[Link](root, text='Click Me', command=lambda: print('Clicked!')) [Link]()
[Link]() # event loop waits for events
UNIT 2: Introduction to Python Programming
2.1 Python Interpreters
An interpreter reads and executes Python code. Several implementations exist:
Interpreter Description
CPython Official & most widely used. Written in C. Compiles .py to .pyc
bytecode, then executes via Python VM. Default when you
install Python from [Link].
IDLE Integrated Development and Learning Environment. Ships
with CPython. Provides a simple GUI editor and interactive
shell. Good for beginners.
Jupyter Notebook Browser-based interactive environment. Code runs in cells.
Supports inline output, visualizations, and markdown. Widely
used in data science.
PyPy Alternative implementation focused on speed using JIT
compilation. Faster for long-running programs.
Jython Python implemented in Java — runs on the JVM. Can use
Java libraries.
2.2 Python Environment Setup
Installation Steps
• 1. Download Python from [Link]
• 2. Run installer — check 'Add Python to PATH' on Windows
• 3. Verify: open terminal and type python --version or python3 --version
• 4. pip (Python package installer) is included; verify with pip --version
python --version # Python 3.x.x pip install numpy # install packages
python [Link] # run a script
.py Files
Python source code files have the .py extension. They are plain text files containing Python statements.
Run them with:
python [Link] # Windows/Linux/Mac python3 [Link] #
Linux/Mac if both Python 2 & 3 installed
2.3 Comments
Single-line Comments
Start with the # symbol. Everything after # on that line is ignored by the interpreter.
# This is a single-line comment x = 10 # This is an inline comment
Multi-line Comments
Python has no dedicated multi-line comment syntax. Use consecutive # lines or triple-quoted strings
(which act as comments if not assigned to a variable).
# Line 1 of comment # Line 2 of comment # Line 3 of comment """This is a multi-
line string often used as a block comment or docstring.""" '''Also valid with
single quotes'''
2.4 input() and print() Functions
print() Function
Used to display output to the console. Can print multiple items, format strings, and control end
character and separator.
print('Hello World') # Hello World print('a', 'b', 'c')
# a b c print('a', 'b', sep='-') # a-b print('Hello', end='!')
# Hello! (no newline) name = 'Alice' print(f'Hello, {name}!') # f-
string formatting print('Value:', 42, type(42)) # Value: 42 <class 'int'>
input() Function
Reads a line of text from the user (standard input). Always returns a string. Use type conversion to get
numbers.
name = input('Enter your name: ') # returns string age = int(input('Enter
age: ')) # convert to int price = float(input('Enter price: ')) #
convert to float print(f'Hello {name}, you are {age} years old.')
2.5 Syntax & Variables
Key Python Syntax Rules
• Indentation defines code blocks (not curly braces like C/Java)
• Standard indentation: 4 spaces per level (PEP 8)
• Statements typically end at the end of a line (no semicolons needed)
• Case-sensitive: name, Name, and NAME are different variables
• Use backslash \ or parentheses () to continue long lines
Variables
A variable is a named storage location. In Python, variables are created by assignment — no type
declaration needed. Python uses dynamic typing.
x = 10 # integer name = 'Alice' # string pi = 3.14 # float
is_valid = True # boolean # Multiple assignment a, b, c = 1, 2, 3 x = y = z =
0 # all point to 0
Variable Naming Rules
• Must start with a letter or underscore (_)
• Can contain letters, numbers, underscores
• Cannot start with a number
• Cannot be a Python keyword (if, for, class, etc.)
• Convention: use snake_case for variables and functions (e.g., my_variable)
2.6 Hello World Program
# My first Python program print('Hello, World!') # Interactive version name =
input('What is your name? ') print(f'Hello, {name}! Welcome to Python.')
📝 Python's 'Hello World' is just one line — a stark contrast to Java's 5+ lines. This simplicity is a
core feature of Python.
2.7 Virtual Environments (venv)
A virtual environment is an isolated Python environment with its own packages and dependencies. It
prevents conflicts between projects that require different versions of the same library.
Why Use venv?
• Project A needs Django 3.2, Project B needs Django 4.2 → use separate venvs
• Keeps global Python installation clean
• Makes projects reproducible ([Link])
venv Commands
# Create a virtual environment python -m venv myenv # Activate (Windows) myenv\
Scripts\activate # Activate (Mac/Linux) source myenv/bin/activate # Install
packages inside venv pip install requests # Save dependencies pip freeze >
[Link] # Install from requirements pip install -r [Link] #
Deactivate deactivate
💡 Always create a venv for each project. Check that (myenv) appears in your terminal prompt —
that confirms the venv is active.
UNIT 3: Data Types
3.1 Built-in Data Types
Python provides several built-in data types. Every value in Python has a type, and you can check it
using the type() function.
Category Type(s)
Numeric int, float, complex
Boolean bool (True or False)
Text str (string)
Sequence list, tuple, range
Mapping dict (dictionary)
Set set, frozenset
None type NoneType (value: None)
Numeric Types
x = 10 # int: whole numbers, unlimited precision y = 3.14 #
float: decimal numbers (IEEE 754 double) z = 2 + 3j # complex: real +
imaginary part print(type(x)) # <class 'int'> print(type(y)) # <class
'float'> print(type(z)) # <class 'complex'>
Boolean Type
bool is a subclass of int. True == 1 and False == 0.
is_active = True print(type(is_active)) # <class 'bool'> print(True + True)
# 2 (bool is subclass of int) print(bool(0)) # False
print(bool('hello')) # True (non-empty string)
String (str)
An immutable sequence of Unicode characters. Can use single, double, or triple quotes.
s1 = 'hello' s2 = "world" s3 = '''multi line''' print(len(s1)) # 5
print([Link]()) # HELLO print(s1[0]) # h (indexing)
print(s1[1:4]) # ell (slicing)
List
An ordered, mutable (changeable) sequence. Can hold items of different types.
lst = [1, 'hello', 3.14, True] [Link](5) # [1, 'hello', 3.14,
True, 5] print(lst[0]) # 1 print(lst[-1]) # 5 (last
element) print(lst[1:3]) # ['hello', 3.14] lst[0] = 99 #
mutable! nested = [[1,2],[3,4]] # nested list print(nested[0][1]) # 2
Tuple
An ordered, immutable sequence. Once created, cannot be modified. Faster than lists.
t = (1, 2, 3) print(t[0]) # 1 # t[0] = 9 # ERROR! tuples are
immutable coords = (10, 20) # common use: x, y coordinates x, y = coords #
unpacking
Dictionary (dict)
An unordered (Python 3.7+ preserves insertion order) collection of key-value pairs. Keys must be
unique and immutable.
d = {'name': 'Alice', 'age': 25, 'city': 'Delhi'} print(d['name']) #
Alice (key access) d['email'] = 'a@[Link]' # insertion del d['city']
# deletion print([Link]()) # dict_keys(['name', 'age', 'email'])
print([Link]('phone', 'N/A')) # safe access with default
Set
An unordered collection of unique elements. No duplicates. Mutable. Useful for membership tests and
set operations.
s = {1, 2, 3, 3, 2} # {1, 2, 3} — duplicates removed [Link](4) print(3 in s)
# True a = {1, 2, 3} b = {2, 3, 4} print(a | b) # union: {1, 2, 3, 4}
print(a & b) # intersection: {2, 3} print(a - b) # difference: {1} print(a
^ b) # symmetric diff: {1, 4}
NoneType
None represents the absence of a value. It is the single instance of NoneType. Functions that don't
explicitly return a value return None.
x = None print(type(x)) # <class 'NoneType'> print(x is None) # True
(use 'is', not '==') def greet(): # no return statement print('Hi')
result = greet() # result is None
3.2 Type Conversion
Implicit Conversion (Coercion)
Python automatically converts a smaller/simpler type to a larger/more complex type when needed to
avoid data loss.
x = 5 # int y = 2.0 # float z = x + y # Python auto-converts x to float
print(z) # 7.0 print(type(z)) # <class 'float'>
Explicit Conversion (Type Casting)
You manually convert a type using built-in functions: int(), float(), str(), bool(), list(), tuple(), set(), dict().
int('42') # 42 (string to int) float('3.14') # 3.14 (string to
float) str(100) # '100' (int to string) bool(0) # False
bool('') # False bool('hello') # True list((1,2,3)) #
[1,2,3] (tuple to list) tuple([1,2,3]) # (1,2,3) (list to tuple)
set([1,1,2,3]) # {1,2,3} (list to set) # Be careful: int('3.14') #
ERROR! Can't convert float-string directly to int int(float('3.14')) # 3 ✓
(correct way)
3.3 Type Checking
x = 42 print(type(x)) # <class 'int'> print(type(x) == int)
# True # isinstance() — preferred: also checks inheritance print(isinstance(x,
int)) # True print(isinstance(x, (int, float))) # True if either
print(isinstance(True, int)) # True! bool is subclass of int
📝 Use isinstance() over type() == X because isinstance() correctly handles inheritance (e.g., bool
is a subclass of int).
UNIT 4: Operators
4.1 Arithmetic Operators
Operator Meaning & Example
+ Addition: 5 + 3 = 8
- Subtraction: 5 - 3 = 2
* Multiplication: 5 * 3 = 15
/ Division (float): 7 / 2 = 3.5
// Floor Division (integer): 7 // 2 = 3
% Modulus (remainder): 7 % 2 = 1
** Exponentiation: 2 ** 3 = 8
4.2 Comparison (Relational) Operators
Return True or False. Used in conditions.
Operator Meaning & Example
== Equal to: 5 == 5 → True
!= Not equal: 5 != 3 → True
> Greater than: 5 > 3 → True
< Less than: 3 < 5 → True
>= Greater or equal: 5 >= 5 → True
<= Less or equal: 3 <= 4 → True
4.3 Logical Operators
Operator Meaning & Example
and Both conditions True: (5>3 and 2<4) → True
or At least one True: (5>10 or 2<4) → True
not Reverses truth value: not True → False
4.4 Assignment Operators
Operator Equivalent to
x=5 Assign 5 to x
x += 3 x=x+3
x -= 3 x=x-3
x *= 3 x=x*3
x /= 3 x=x/3
x //= 3 x = x // 3
x **= 3 x = x ** 3
x %= 3 x=x%3
4.5 Bitwise Operators
Operate on integers at the binary bit level.
Operator Name & Example (a=5=0101, b=3=0011)
& AND: 5 & 3 = 0001 = 1
| OR: 5 | 3 = 0111 = 7
^ XOR: 5 ^ 3 = 0110 = 6
~ NOT: ~5 = -6 (flips all bits)
<< Left shift: 5 << 1 = 10 (multiply by 2)
>> Right shift: 5 >> 1 = 2 (divide by 2)
4.6 Identity & Membership Operators
Identity Operators
Check whether two variables refer to the SAME object in memory (not just equal values).
a = [1, 2, 3] b = a # b points to same object c = [1, 2, 3] # c is a
different object print(a is b) # True (same object) print(a is c) #
False (different objects, same value) print(a is not c) # True
📝 Use 'is' only for None checks (x is None) and comparing singletons. For value comparison,
always use ==.
Membership Operators
Check whether a value exists in a sequence (string, list, tuple, dict, set).
fruits = ['apple', 'banana', 'cherry'] print('banana' in fruits) # True
print('mango' in fruits) # False print('mango' not in fruits) # True
text = 'Hello World' print('World' in text) # True d = {'key':
'value'} print('key' in d) # True (checks keys)
4.7 Operator Precedence (Highest to Lowest)
Precedence Operators
1 (Highest) () — Parentheses
2 ** — Exponentiation
3 +x, -x, ~x — Unary operators
4 *, /, //, % — Multiplication/Division
5 +, - — Addition/Subtraction
6 <<, >> — Bitwise shifts
7 & — Bitwise AND
8 ^ — Bitwise XOR
9 | — Bitwise OR
10 ==, !=, >, <, >=, <=, is, is not, in, not in
11 not — Logical NOT
12 and — Logical AND
13 (Lowest) or — Logical OR
💡 PEMDAS/BODMAS applies! Always use parentheses to make precedence explicit and code
readable.
UNIT 5: Operations on Data Structures
5.1 String Operations
Concatenation
s1 = 'Hello' s2 = ' World' result = s1 + s2 # 'Hello World' name = 'Alice'
greeting = 'Hello, ' + name + '!'
Repetition
s = 'ha' print(s * 3) # 'hahaha' print('-' * 20) # --------------------
Slicing & Indexing
Strings use zero-based indexing. Negative indices count from the end.
s = 'Python' # Indexing print(s[0]) # P (first character) print(s[-1])
# n (last character) # Slicing: s[start:stop:step] print(s[0:3]) # Pyt
(index 0,1,2 — stop is exclusive) print(s[2:]) # thon (from index 2 to end)
print(s[:4]) # Pyth (from start to index 3) print(s[::2]) # Pto (every 2nd
character) print(s[::-1]) # nohtyP (reversed)
Common String Methods
s = 'Hello World' print([Link]()) # HELLO WORLD print([Link]())
# hello world print([Link]()) # removes leading/trailing spaces
print([Link]()) # ['Hello', 'World'] print([Link]('World',
'Python')) # Hello Python print([Link]('World')) # 6 (index of first
occurrence) print([Link]('Hello')) # True print([Link]('l')) # 3
print(','.join(['a','b','c'])) # a,b,c
5.2 List Operations
lst = [10, 20, 30, 40, 50] # Indexing print(lst[0]) # 10 print(lst[-1])
# 50 # Slicing print(lst[1:4]) # [20, 30, 40] print(lst[::2]) # [10, 30,
50] # Appending [Link](60) # adds to end [Link](0, 5)
# inserts at index 0 # Modifying lst[0] = 99 # mutable! #
Removing [Link](99) # removes first occurrence popped = [Link]()
# removes & returns last popped = [Link](0) # removes & returns at index
0 # Other operations print(len(lst)) # length [Link]()
# sort in-place [Link]() # reverse in-place
print([Link](30)) # find index of value print(20 in lst) # True
(membership)
Nested Lists
matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] print(matrix[0][0]) #
1 (row 0, col 0) print(matrix[1][2]) # 6 (row 1, col 2) # Iterate for row in
matrix: for val in row: print(val, end=' ')
5.3 Dictionary Operations
d = {'name': 'Alice', 'age': 25} # Key access print(d['name']) #
Alice print([Link]('phone', 'N/A')) # N/A (safe — no KeyError) # Insertion /
Update d['email'] = 'a@[Link]' # add new key d['age'] = 26 #
update existing key [Link]({'city': 'Mumbai', 'age': 27}) # bulk update #
Deletion del d['email'] # delete key removed = [Link]('age') #
remove & return value # Iteration for key in d: # iterate keys
print(key, d[key]) for k, v in [Link](): # iterate key-value pairs
print(f'{k}: {v}') # Dictionary methods print([Link]()) #
dict_keys([...]) print([Link]()) # dict_values([...]) print([Link]())
# dict_items([...])
5.4 Set Operations
a = {1, 2, 3, 4} b = {3, 4, 5, 6} # Union — all elements from both print(a | b)
# {1, 2, 3, 4, 5, 6} print([Link](b)) # Intersection — common elements print(a
& b) # {3, 4} print([Link](b)) # Difference — in a but not b print(a
- b) # {1, 2} print([Link](b)) # Symmetric Difference — in either but
not both print(a ^ b) # {1, 2, 5, 6} print(a.symmetric_difference(b)) #
Membership test print(3 in a) # True # Other [Link](99) [Link](99) # no
error if not found [Link](99) # raises KeyError if not found
UNIT 6: Control Structures
6.1 Conditional Statements
if-else Statement
Execute different code blocks based on a condition.
age = int(input('Enter age: ')) if age >= 18: print('Adult') elif age >= 13:
print('Teenager') else: print('Child')
Nested if
x = 15 if x > 0: if x > 10: print('Greater than 10') else:
print('Between 1 and 10') else: print('Non-positive')
Ternary (Inline if)
x = 10 result = 'Even' if x % 2 == 0 else 'Odd' print(result) # Even
6.2 Loops
while Loop
Repeats as long as a condition is True.
count = 1 while count <= 5: print(count) count += 1 # Infinite loop
with break while True: user = input('Type quit to exit: ') if user ==
'quit': break
for Loop
Iterates over a sequence (list, tuple, string, range, dict, set).
# Iterate over a list for fruit in ['apple', 'banana', 'cherry']:
print(fruit) # Iterate with range() for i in range(5): # 0,1,2,3,4
print(i) for i in range(1, 11): # 1 to 10 print(i) for i in range(0, 10,
2): # 0,2,4,6,8 (step 2) print(i) # Iterate over string for char in
'Python': print(char) # Iterate over dictionary d = {'a': 1, 'b': 2} for
key, value in [Link](): print(key, value) # enumerate — get index and
value for i, val in enumerate(['a','b','c']): print(i, val) # 0 a, 1 b, 2 c
break Statement
Exits the innermost loop immediately.
for i in range(10): if i == 5: break # exit loop when i is 5
print(i) # prints 0 1 2 3 4
continue Statement
Skips the rest of the current iteration and continues with the next.
for i in range(10): if i % 2 == 0: continue # skip even numbers
print(i) # prints 1 3 5 7 9
for-else and while-else
The else block runs if the loop completes normally (without break).
for i in range(5): if i == 10: # never true break else:
print('Loop completed without break') # this runs
UNIT 7: Functions
7.1 Why Functions?
• Modular Programming: Break large programs into manageable pieces
• Reusability: Write once, use many times
• Readability: Named functions describe what code does
• Maintainability: Fix a bug in one place, not everywhere
7.2 Defining & Calling Functions
# Definition def greet(name): """Greet a person by name.""" # docstring
print(f'Hello, {name}!') # Call greet('Alice') # Hello, Alice! greet('Bob')
# Hello, Bob!
📝 Naming convention: use snake_case for function names (e.g., calculate_area,
get_user_name).
7.3 Types of Arguments
Positional Arguments
def add(a, b): return a + b print(add(3, 4)) # 7 (order matters)
Keyword Arguments
def greet(first, last): print(f'{first} {last}') greet(last='Smith',
first='John') # order doesn't matter
Default Arguments
def power(base, exp=2): # exp has a default return base ** exp
print(power(3)) # 9 (exp defaults to 2) print(power(3, 3)) # 27
Variable-Length Arguments (*args)
*args collects extra positional arguments into a tuple.
def total(*args): return sum(args) print(total(1, 2, 3)) # 6
print(total(10, 20, 30, 40)) # 100
Keyword Variable-Length (**kwargs)
**kwargs collects extra keyword arguments into a dictionary.
def show_info(**kwargs): for key, val in [Link]():
print(f'{key}: {val}') show_info(name='Alice', age=25, city='Delhi') # name:
Alice / age: 25 / city: Delhi
Command Line Arguments
import sys # Run as: python [Link] Alice 25 name = [Link][1] # 'Alice'
age = [Link][2] # '25' print(f'{name} is {age} years old.')
7.4 Variable Scope & Lifetime
Local Scope
Variables defined inside a function are local — only accessible within that function.
def func(): x = 10 # local variable print(x) func() # 10 #
print(x) # NameError! x not accessible here
Global Scope
Variables defined at the module level are global.
count = 0 # global def increment(): global count # tell Python we mean
the global variable count += 1 increment() print(count) # 1
📝 Avoid excessive use of global variables — they make code hard to debug. Prefer passing
values as arguments.
7.5 Recursion
A function that calls itself is recursive. Every recursive function needs a base case (to stop recursion)
and a recursive case.
Factorial
def factorial(n): if n == 0 or n == 1: # base case return 1
return n * factorial(n - 1) # recursive case print(factorial(5)) # 120
(5*4*3*2*1)
Fibonacci
def fibonacci(n): if n <= 0: return 0 # base case if n == 1:
return 1 # base case return fibonacci(n-1) + fibonacci(n-2) #
recursive for i in range(8): print(fibonacci(i), end=' ') # 0 1 1 2 3 5 8
13
7.6 Lambda Functions
Anonymous (nameless) functions defined with the lambda keyword. Used for short, one-line functions.
# Syntax: lambda arguments: expression square = lambda x: x ** 2
print(square(5)) # 25 add = lambda a, b: a + b print(add(3, 4))
# 7 # Common use with map(), filter(), sorted() nums = [1, 2, 3, 4, 5] squares
= list(map(lambda x: x**2, nums)) # [1,4,9,16,25] evens = list(filter(lambda
x: x%2==0, nums)) # [2,4] # sort by second element of tuple pairs = [(1,'b'),
(3,'a'), (2,'c')] [Link](key=lambda x: x[1]) print(pairs) # [(3,'a'),
(1,'b'), (2,'c')]
7.7 Docstrings
def calculate_area(length, width): """ Calculate the area of a
rectangle. Args: length (float): The length of the rectangle.
width (float): The width of the rectangle. Returns: float: The
area. """ return length * width print(calculate_area.__doc__) #
access docstring
UNIT 8: Classes and Objects (OOP)
8.1 Procedural vs OOP
Procedural Object-Oriented
Organized around Organized around objects
functions/procedures
Data and functions are separate Data and functions bundled in classes
Top-down design Bottom-up design
Less modeling of real world Models real-world entities naturally
C, Pascal Python, Java, C++
8.2 Classes and Objects
A class is a blueprint/template. An object is an instance of a class — a concrete entity created from the
blueprint.
class Dog: # class definition (PascalCase naming) """Represents a
dog.""" species = 'Canis lupus' # class attribute (shared by all)
def __init__(self, name, breed, age): # instance attributes (unique per
object) [Link] = name [Link] = breed [Link]
= age def bark(self): return f'{[Link]} says: Woof!'
def info(self): return f'{[Link]} ({[Link]}), {[Link]} years
old' # Instantiation (creating objects) dog1 = Dog('Rex', 'Labrador', 3) dog2
= Dog('Bella', 'Poodle', 5) print([Link]()) # Rex says: Woof!
print([Link]()) # Bella (Poodle), 5 years old print([Link]) # Canis
lupus (class attribute) # Accessing and modifying attributes print([Link])
# Rex [Link] = 4 # modify [Link] = 'brown' # add new attribute
dynamically
__init__() Method
The constructor method, called automatically when an object is created. The self parameter refers to
the current instance.
📝 self is always the first parameter in instance methods but is never passed explicitly when
calling — Python passes it automatically.
8.3 Inheritance
A child class inherits all attributes and methods from a parent class. It can add new features or override
existing ones.
class Animal: def __init__(self, name): [Link] = name
def speak(self): return f'{[Link]} makes a sound' def
__str__(self): return f'Animal: {[Link]}' class Dog(Animal):
# Dog inherits from Animal def __init__(self, name, breed):
super().__init__(name) # call parent __init__ [Link] = breed
def speak(self): # method overriding return f'{[Link]} says
Woof!' def fetch(self): return f'{[Link]} fetches the ball'
class Cat(Animal): def speak(self): return f'{[Link]} says Meow!'
d = Dog('Rex', 'Lab') c = Cat('Whiskers') print([Link]()) # Rex says Woof!
(overridden) print([Link]()) # Whiskers says Meow! print([Link]()) # Rex
fetches the ball (Dog-specific) print([Link]) # Rex (inherited attribute)
super()
super() returns a proxy object that allows calling the parent class's methods from the child class.
class Parent: def __init__(self, x): self.x = x class
Child(Parent): def __init__(self, x, y): super().__init__(x) #
calls Parent.__init__ self.y = y
8.4 isinstance() and Class Relationships
d = Dog('Rex', 'Lab') print(isinstance(d, Dog)) # True print(isinstance(d,
Animal)) # True (Dog inherits from Animal) print(isinstance(d, Cat)) #
False print(type(d)) # <class '__main__.Dog'> print(type(d) ==
Dog) # True print(issubclass(Dog, Animal))# True
8.5 Regular Expressions (re module)
Regular expressions (regex) are patterns used to search, match, and manipulate strings.
import re # Common patterns # . any char except newline # \d digit [0-9]
# \w word character [a-zA-Z0-9_] # \s whitespace # + one or more # *
zero or more # ? zero or one # ^ start of string # $ end of string #
[] character class # () grouping text = 'Contact: john@[Link] or
alice123@[Link]' # Search for first match match = [Link](r'\w+@\w+\.\w+',
text) if match: print([Link]()) # john@[Link] # Find all matches
emails = [Link](r'\w+@\w+\.\w+', text) print(emails) #
['john@[Link]', 'alice123@[Link]'] # Match at beginning result =
[Link](r'Contact', text) print(result) # Match object if found
# Replace new_text = [Link](r'\d+', 'NUM', 'Room 101, Floor 5') print(new_text)
# Room NUM, Floor NUM # Validate email email = 'test@[Link]' if
[Link](r'[\w.]+@[\w.]+\.\w+', email): print('Valid email')
UNIT 9: File Handling
9.1 Why Files?
• Persist data beyond program execution
• Share data between programs
• Process large datasets
• Log events and errors
9.2 File Types
Text Files Binary Files
Human readable content Machine-readable encoded content
Stored as characters (ASCII/UTF-8) Stored as raw bytes
Examples: .txt, .csv, .py, .html, .json Examples: .jpg, .pdf, .exe, .mp3, .docx
Opened in text mode ('r', 'w', 'a') Opened in binary mode ('rb', 'wb', 'ab')
9.3 File Opening Modes
Mode Description
'r' Read only (default). Error if file doesn't exist.
'w' Write. Creates file if not exists. Overwrites existing content.
'a' Append. Creates if not exists. Adds to end of existing content.
'x' Create. Error if file already exists.
'r+' Read and Write. File must exist.
'rb' Read binary mode
'wb' Write binary mode
'ab' Append binary mode
9.4 File Operations
Opening and Closing
# Method 1: Manual open/close f = open('[Link]', 'r') # open content =
[Link]() [Link]() # always close! # Method 2: with statement
(PREFERRED — auto closes) with open('[Link]', 'r') as f: content =
[Link]() # file is automatically closed here, even if error occurs
Reading
with open('[Link]', 'r') as f: # read() — entire file as one string
content = [Link]() with open('[Link]', 'r') as f: # readline() — one
line at a time first_line = [Link]() with open('[Link]', 'r') as
f: # readlines() — all lines as a list lines = [Link]() #
['line1\n', 'line2\n'] with open('[Link]', 'r') as f: # Iterate line
by line (memory efficient) for line in f: print([Link]()) #
strip removes \n
Writing
# Write (overwrites) with open('[Link]', 'w') as f: [Link]('Hello
World\n') [Link]('Second line\n') [Link](['a\n', 'b\n', 'c\n'])
# write list # Append with open('[Link]', 'a') as f: [Link]('Appended
line\n')
Deleting a File
import os if [Link]('[Link]'): [Link]('[Link]') else:
print('File not found')
Navigation (seek & tell)
with open('[Link]', 'r') as f: [Link](5) # read 5 characters
print([Link]()) # current position (e.g., 5) [Link](0) # go back
to beginning [Link](0, 2) # go to end (os.SEEK_END)
UNIT 10: Error and Exception Handling
10.1 Types of Errors
Syntax Errors
Mistakes in the code structure that prevent the program from parsing. Detected BEFORE execution.
if x = 5: # SyntaxError: should be == print 'Hello' # SyntaxError:
missing parentheses (Python 3)
Runtime Errors (Exceptions)
Errors that occur DURING execution when something unexpected happens.
Exception Cause
ZeroDivisionError Dividing by zero: 10 / 0
TypeError Wrong type: '2' + 2 (str + int)
NameError Using undefined variable: print(x) before x=...
ValueError Wrong value: int('abc')
IndexError List index out of range: lst[100] on small list
KeyError Dict key not found: d['missing_key']
FileNotFoundError Opening non-existent file
PermissionError No permission to read/write file
AttributeError Accessing non-existent attribute/method
ImportError Module not found: import nonexistent
RecursionError Too many recursive calls
OverflowError Number too large for float
10.2 try-except Blocks
# Basic try: result = 10 / 0 except ZeroDivisionError: print('Cannot
divide by zero!') # Catching the exception object try: x = int('abc')
except ValueError as e: print(f'Error: {e}') # invalid literal for
int()... # Multiple except blocks try: num = int(input('Enter a number: '))
result = 100 / num except ValueError: print('Please enter a valid integer')
except ZeroDivisionError: print('Cannot divide by zero') except Exception as
e: # catch-all (use sparingly) print(f'Unexpected error: {e}') #
Catching multiple in one block try: pass except (TypeError, ValueError) as
e: print(f'Type or Value error: {e}')
10.3 else and finally
try: f = open('[Link]', 'r') data = [Link]() except FileNotFoundError:
print('File not found') else: # Runs only if NO exception occurred
print('File read successfully') print(data) finally: # ALWAYS runs —
used for cleanup print('Execution complete') # [Link]() would go here
(or use with statement)
10.4 raise — Throwing Exceptions
def set_age(age): if age < 0: raise ValueError('Age cannot be
negative') if age > 150: raise ValueError('Age seems unrealistic')
return age try: set_age(-5) except ValueError as e: print(e) # Age
cannot be negative # Re-raising an exception try: x = int('abc') except
ValueError: print('Logging error...') raise # re-raises the caught
exception
10.5 Custom Exceptions
class InsufficientFundsError(Exception): """Raised when account has
insufficient funds.""" def __init__(self, balance, amount):
[Link] = balance [Link] = amount
super().__init__(f'Need {amount}, have {balance}') class BankAccount: def
__init__(self, balance): [Link] = balance def
withdraw(self, amount): if amount > [Link]: raise
InsufficientFundsError([Link], amount) [Link] -= amount
account = BankAccount(100) try: [Link](200) except
InsufficientFundsError as e: print(e) # Need 200, have 100
UNIT 11: Python Best Practices (PEP 8)
11.1 Naming Conventions
Element Convention & Example
Variables snake_case: user_name, total_price, is_valid
Functions snake_case: calculate_area(), get_user_name()
Classes PascalCase: BankAccount, StudentRecord, HttpClient
Constants UPPER_SNAKE_CASE: MAX_SIZE, PI,
DEFAULT_TIMEOUT
Private attributes Leading underscore: _internal_value, __private_var
Modules snake_case: my_module.py, data_utils.py
Packages lowercase: mypackage, utils
11.2 Indentation and Spacing
# ✓ Correct — 4 spaces per level def calculate(a, b): if a > b:
return a - b else: return b - a # ✓ Spaces around operators x = 5 +
3 y = x * 2 # ✓ No spaces inside parentheses result = my_func(a, b) # not
my_func( a , b ) # ✓ One space after comma def func(a, b, c): # not
func(a,b,c) pass
11.3 Line Length and Breaking Long Lines
# PEP 8 recommends max 79 characters per line # Break using parentheses
(preferred) or backslash # Parentheses (implicit continuation) total =
(first_number + second_number + third_number) # Function call
result = my_function( argument_one, argument_two, argument_three )
# Import from module import (ClassA, ClassB,
function_c)
11.4 Modular Organization
# Good: split code into logical files # project/ # │── [Link] # │── [Link] #
│── [Link] # └── __init__.py ← makes directory a package # __init__.py (can
be empty or expose public API) from .models import User from .utils import
helper # In [Link]: from utils import calculate from models import User
11.5 Useful Built-in Functions
# enumerate — index + value for i, val in enumerate(['a','b','c'], start=1):
print(i, val) # 1 a, 2 b, 3 c # zip — combine iterables names = ['Alice',
'Bob', 'Carol'] scores = [85, 92, 78] for name, score in zip(names, scores):
print(f'{name}: {score}') # any — True if any element is truthy print(any([0,
0, 1, 0])) # True print(any([0, 0, 0])) # False # all — True if all
elements are truthy print(all([1, 2, 3])) # True print(all([1, 0, 3]))
# False # sorted with key words = ['banana', 'apple', 'cherry']
print(sorted(words, key=len)) # by length print(sorted(words, reverse=True))
# descending # map and filter nums = [1, 2, 3, 4, 5] print(list(map(str,
nums))) # ['1','2','3','4','5'] print(list(filter(lambda x: x>2,
nums)))# [3,4,5] # List comprehensions (Pythonic style) squares = [x**2 for x
in range(10)] evens = [x for x in range(20) if x % 2 == 0]
11.6 Comments: Inline vs Block
# Block comment: explains the section below # This function calculates compound
interest def compound_interest(principal, rate, time): return principal *
((1 + rate) ** time) x = x + 1 # Inline comment: compensate for off-by-one #
BAD: stating the obvious (avoid this) x = x + 1 # adds 1 to x ← useless, we
can see that
📝 Comments should explain WHY, not WHAT. The code already shows what. Good comments
explain intent, edge cases, and decisions.
11.7 Quick Summary: Python Best Practices
• Use meaningful, descriptive variable names
• Follow PEP 8 naming conventions (snake_case for vars/functions, PascalCase for classes)
• Keep functions small and focused on one task
• Use docstrings for all public modules, classes, functions
• Prefer with statements for file handling
• Use isinstance() instead of type() for type checking
• Use list/dict/set comprehensions for concise code
• Avoid bare except: clauses — always catch specific exceptions
• Don't use global variables unless absolutely necessary
• Use virtual environments for every project
• Write comments explaining WHY, not WHAT
EXAM QUICK REFERENCE SHEET
Python Data Type Comparison
Type Ordered
list Yes
tuple Yes
set No
dict Yes (3.7+)
str Yes
Function Argument Order
def func(pos1, pos2, # positional kw1='default',
# keyword/default *args, # extra positional
**kwargs): # extra keyword pass
📝 Order must be: positional → default → *args → **kwargs
Common String Escape Sequences
Escape Meaning
\n Newline
\t Tab
\\ Backslash
\' Single quote
\" Double quote
\r Carriage return
OOP Pillar Summary
Pillar Definition
Encapsulation Bundling data + methods; restricting direct access to internals
Abstraction Hiding implementation complexity; showing only necessary
details
Inheritance Child class acquires properties/methods of parent class
Polymorphism Same method name, different behavior in different classes
Exception Handling Template
try: # Code that might raise an exception risky_operation() except
SpecificError as e: # Handle specific exception print(f'Error: {e}')
except (AnotherError, YetAnother) as e: # Handle multiple exceptions
pass else: # Only runs if NO exception was raised print('Success!')
finally: # ALWAYS runs — cleanup code cleanup()
File Handling Template
import os # Reading with open('[Link]', 'r', encoding='utf-8') as f:
content = [Link]() # whole file # OR for line in f:
# line by line process([Link]()) # Writing with open('[Link]',
'w', encoding='utf-8') as f: [Link]('content\n') # Check existence if
[Link]('[Link]'): [Link]('[Link]')
Common Regex Patterns
Pattern Matches
\d+ One or more digits
\w+ One or more word characters
\s+ One or more whitespace
[A-Z] Single uppercase letter
^\d{3}-\d{4}$ Phone pattern: 123-4567
[\w.]+@[\w.]+\.\w+ Simple email pattern
https?://\S+ URL starting with http or https
━━━ ALL THE BEST FOR YOUR EXAM! ━━━
Understand concepts, practice code, and you'll ace it.