# Notes on Programming & Python ## 1. What is a Programming Language? * A **programming language** is a set of instructions, rules, and syntax that allows humans to communicate with computers. * It is used to write programs that tell the computer what to do. * Examples: Python, C, Java, JavaScript. --- ## 2. Types of Programming Languages ### (a) Low-Level Languages * Closer to machine code (binary). * Harder for humans to understand but very fast for computers. * Examples: * **Machine Language** (direct 0s and 1s). * **Assembly Language** (uses short codes like `MOV`, `ADD`). * Advantages: High speed, efficient use of memory. * Disadvantages: Difficult to write and understand. ### (b) High-Level Languages * Closer to human language, easier to write and understand. * Uses English-like syntax. * Examples: Python, Java, C++, JavaScript. * Advantages: Easy to learn, portable across platforms. * Disadvantages: Slightly slower than low-level languages (because they need translation). --- ## 3. What is Python? * Python is a **high-level, interpreted, and general-purpose programming language**. * Created by **Guido van Rossum** in **1991**. * Known for being **simple, readable, and versatile**. * Used in: Web development, Data Science, Machine Learning, Artificial Intelligence, Automation, etc. --- ## 4. Python Installation and VS Code ### Installing Python 1. Go to [python.org](https://www.python.org/downloads/). 2. Download the latest version for your OS (Windows/Mac/Linux). 3. Install and make sure to check **“Add Python to PATH”**. ### Installing VS Code 1. Download from [code.visualstudio.com](https://code.visualstudio.com/). 2. Install and open. 3. Install the **Python extension** from VS Code marketplace. 4. Set interpreter: `Ctrl + Shift + P` → "Python: Select Interpreter". --- ## 5. Python Execution Process Python code can be executed in **two main ways**: 1. **Interactive Mode** * Open terminal and type `python` or `python3`. * Write code line by line and get instant output. * Example: ```python >>> print("Hello, World!") Hello, World! ``` 2. **Script Mode** * Write code in a `.py` file (example: `program.py`). * Run it in terminal with: ```bash python program.py ``` **Execution Process Behind the Scenes**: * Python code → **Python Interpreter** → **Bytecode** → **Python Virtual Machine (PVM)** → Output. ![Python Execution Process](https://hackmd.io/_uploads/BkNeLvJKlg.png) --- ## 5. Variables in Python * A **variable** is a name that stores a value in memory. * It acts like a container for data. * Example: ```python x = 10 # integer name = "Ram" # string temperature = 28.6 # float ``` --- ## 6. Variable Naming Rules * Variable names must follow these rules: 1. Can only contain letters (a-z, A-Z), digits (0-9), and underscores `_`. 2. Must **start with a letter or underscore**, not a digit. 3. Case-sensitive (`age`, `Age`, and `AGE` are different). 4. Cannot use Python **keywords** (like `for`, `if`, `while`, `class`). ✅ Valid examples: ```python student_name = "Hari" _age = 25 number1 = 100 ``` ❌ Invalid examples: ```python 1number = 50 # cannot start with digit student-name = "Hari" # cannot use '-' for = 10 # keyword not allowed ``` --- ## 7. Snake Case Naming Convention * In Python, variable names usually follow **snake\_case** style. * Words are written in **lowercase** and separated by underscores `_`. * Example: ```python student_age = 20 total_marks = 480 average_score = 96 ``` --- ## 8. Constants in Python * A **constant** is a variable whose value should not change throughout the program. * Python does not have true constants, but by **naming convention** we use **UPPERCASE letters**. * Example: ```python PI = 3.14159 GRAVITY = 9.8 MAX_USERS = 100 ``` --- ## 10. Comments in Python - **Comments** are notes inside the code that Python ignores during execution. - Used to explain code and make it easier to understand. ### Types of Comments 1. **Single-line Comment** ```python # This is a single-line comment print("Hello, World!") 1. **Multi-line Comment** ```python ''' This is a multi-line comment ''' --- ## 11. Advantages of Comments * Makes code easier to read and understand. * Helps other programmers (or future you) know what the code does. * Useful for debugging (can “comment out” code temporarily). * Acts as documentation for projects. --- ## 12. Data Types in Python ### Need of Data Types * Define **what kind of value** is stored in a variable. * Help Python decide: 1. How much memory is required. 2. What operations are allowed. 3. How the value is represented internally. **Example** * `10 + 20 = 30` → numbers are added * `"10" + "20" = "1020"` → strings are concatenated --- ### Classification of Data Types 1. **Primitive Data Types** (basic types) 2. **Non-Primitive Data Types** (collections, user-defined) → *Will study later* --- ### Primitive Data Types in Python * **Integer (`int`)** → whole numbers ```python age = 25 ``` * **Float (`float`)** → decimal numbers ```python PI = 3.14 ``` * **Complex (`complex`)** → real + imaginary ```python z = 2 + 3j ``` * **String (`str`)** → text data ```python name = "Ram" ``` * **Boolean (`bool`)** → truth values ```python is_student = True ``` * **NoneType (`None`)** → represents no value ```python x = None ``` --- # Python Primitive Data Types ## 13. Integer (`int`) * **Definition:** Whole numbers without decimal points. * **Usage:** Counting, indexing, arithmetic calculations. * **Examples:** ```python age = 25 year = 2025 balance = -100 ``` * **Operations:** 1. Addition: `+` → `5 + 3 = 8` 2. Subtraction: `-` → `5 - 3 = 2` 3. Multiplication: `*` → `5 * 3 = 15` 4. Division: `/` → `5 / 2 = 2.5` (returns float) 5. Floor division: `//` → `5 // 2 = 2` (integer result) 6. Modulus: `%` → `5 % 2 = 1` (remainder) 7. Exponent: `**` → `5 ** 2 = 25` --- ## 14. Floating Point (`float`) * **Definition:** Numbers with decimal points. * **Usage:** Measurements, money, scientific calculations. * **Examples:** ```python price = 99.99 temperature = -4.5 PI = 3.14159 ``` * **Operations:** Same as integers, results may include decimal points. ```python a = 5.0 b = 2.0 print(a / b) # 2.5 print(a // b) # 2.0 ``` * **Note:** Division `/` always returns a float. --- ## 15. Boolean (`bool`) * **Definition:** Data type with only **two values**: `True` or `False`. * **Usage:** Represent conditions, control flow, and logical operations. * **Examples:** ```python is_active = True is_logged_in = False ``` ### 15.1 Boolean Operations 1. `and` → True if **both True** 2. `or` → True if **at least one True** 3. `not` → Reverses the value ```python a = True b = False print(a and b) # False print(a or b) # True print(not a) # False ``` ### 15.2 Logical Operator Precedence * **Logical Operator Precedence** in Python (from highest to lowest): 1. `not` → evaluated first 2. `and` → evaluated second 3. `or` → evaluated last * **Example:** ```python a = True b = False c = True result = a or b and not c # Step 1: not c → not True → False # Step 2: b and False → False and False → False # Step 3: a or False → True or False → True print(result) # True ``` --- ## 16. Operators in Python Operators are symbols that **perform operations** on values or variables. Python supports several types of operators. --- ### 16.1 Arithmetic Operators * Used to perform **mathematical calculations**. | Operator | Description | Example | | -------- | ------------------- | ------------- | | `+` | Addition | `5 + 3 = 8` | | `-` | Subtraction | `5 - 3 = 2` | | `*` | Multiplication | `5 * 3 = 15` | | `/` | Division | `5 / 2 = 2.5` | | `//` | Floor Division | `5 // 2 = 2` | | `%` | Modulus (remainder) | `5 % 2 = 1` | | `**` | Exponentiation | `5 ** 2 = 25` | ```python a = 7 b = 3 print(a + b) # 10 print(a ** b) # 343 ``` --- ### 16.2 Comparison Operators * Used to **compare values**. Returns **Boolean** (`True` or `False`). | Operator | Description | Example | | -------- | ---------------- | ---------------- | | `==` | Equal | `5 == 3 → False` | | `!=` | Not equal | `5 != 3 → True` | | `>` | Greater than | `5 > 3 → True` | | `<` | Less than | `5 < 3 → False` | | `>=` | Greater or equal | `5 >= 5 → True` | | `<=` | Less or equal | `3 <= 5 → True` | ```python x = 10 y = 20 print(x < y) # True print(x == y) # False ``` --- ### 16.3 Assignment Operators * Used to **assign values** to variables. | Operator | Description | Example | | -------- | ----------------------- | ---------------------- | | `=` | Assign | `x = 5` | | `+=` | Add and assign | `x += 3 → x = x + 3` | | `-=` | Subtract and assign | `x -= 2 → x = x - 2` | | `*=` | Multiply and assign | `x *= 2 → x = x * 2` | | `/=` | Divide and assign | `x /= 2 → x = x / 2` | | `//=` | Floor divide and assign | `x //= 3 → x = x // 3` | | `%=` | Modulus and assign | `x %= 2 → x = x % 2` | | `**=` | Exponent and assign | `x **= 3 → x = x ** 3` | ```python x = 5 x += 3 print(x) # 8 ``` --- ### 16.4 Logical Operators * Used to **combine Boolean values** or expressions. | Operator | Description | Example | | -------- | ---------------------------------- | ------------------------ | | `and` | True if **both** operands are True | `True and False → False` | | `or` | True if **at least one** is True | `True or False → True` | | `not` | Inverts the Boolean value | `not True → False` | ```python a = True b = False print(a and b) # False print(a or b) # True print(not a) # False ``` * **Operator Precedence (highest → lowest):** 1. `()` → Parentheses 2. Arithmetic (`**, *, /, //, %, +, -`) 3. Comparison (`==, !=, >, <, >=, <=`) 4. Logical `not` 5. Logical `and` 6. Logical `or` ```python result = True or False and not False # Step 1: not False → True # Step 2: False and True → False # Step 3: True or False → True print(result) # True ``` --- ## 17. String (`str`) * **Definition:** A **string** is a **sequence of characters** enclosed in **single quotes `' '`** or **double quotes `" "`**. * **Usage:** Used to store text, messages, names, or any sequence of characters. ```python name = "Ram" greeting = 'Hello' message = "Python is fun!" ``` --- ### 17.1 String Creation * Using **single quotes** `'...'` * Using **double quotes** `"..."` * Using **triple quotes** `'''...'''` or `"""..."""` for **multiline strings** ```python single = 'Hello' double = "World" multiline = """This is a multiline string""" print(multiline) ``` --- ### 17.2 String Indexing * Each character in a string has an **index** starting from **0**. * **Negative indexing** starts from the **end** of the string (`-1` = last character). ```python text = "Python" print(text[0]) # P print(text[3]) # h print(text[-1]) # n print(text[-2]) # o ``` --- ### 17.3 String Slicing * Extract a **substring** using **start\:stop\:step** format: ```python text = "Python" print(text[0:4]) # Pyth (index 0 to 3) print(text[2:]) # thon (from index 2 to end) print(text[:4]) # Pyth (from start to index 3) print(text[::2]) # Pto (every 2nd character) print(text[::-1]) # nohtyP (reversed string) ``` --- ### 17.4 String Operations 1. **Concatenation (`+`)** → Combine strings ```python first = "Hello" second = "World" result = first + " " + second print(result) # Hello World ``` 2. **Repetition (`*`)** → Repeat strings ```python text = "Ha" print(text * 3) # HaHaHa ``` 3. **Length (`len()`)** → Number of characters ```python text = "Python" print(len(text)) # 6 ``` --- ### 17.5 String Methods | Method | Description | Example | | ------------------ | ----------------------------------------------------- | ----------------------------------------------------- | | `upper()` | Converts string to uppercase | `"hi".upper() → "HI"` | | `lower()` | Converts string to lowercase | `"HELLO".lower() → "hello"` | | `capitalize()` | Capitalizes first character | `"hello".capitalize() → "Hello"` | | `title()` | Capitalizes first letter of each word | `"python programming".title() → "Python Programming"` | | `strip()` | Removes leading and trailing spaces | `" hi ".strip() → "hi"` | | `replace(old,new)` | Replaces substring | `"Hello".replace("H","J") → "Jello"` | | `split(separator)` | Splits string into list | `"a,b,c".split(",") → ["a","b","c"]` | | `join(iterable)` | Joins iterable elements into string | `"-".join(["a","b","c"]) → "a-b-c"` | | `find(sub)` | Returns first index of substring (or -1 if not found) | `"Python".find("t") → 3` | ```python text = " Python " print(text.strip()) # "Python" print("Hello World".upper()) # "HELLO WORLD" print("a,b,c".split(",")) # ['a', 'b', 'c'] ``` --- ### 17.6 String Formatting 1. **Using f-strings (Python 3.6+)** ```python name = "Ram" age = 30 print(f"My name is {name} and I am {age} years old.") ``` 2. **Using `format()` method** ```python print("My name is {} and I am {} years old.".format(name, age)) ``` --- ### 17.7 String Escape Characters * Special characters to represent certain actions: | Escape | Meaning | | ------ | ------------ | | `\n` | Newline | | `\t` | Tab | | `\\` | Backslash | | `\'` | Single quote | | `\"` | Double quote | ```python print("Hello\nWorld") print("Hello\tWorld") print("I am 5\'10\" tall") ``` --- ### 17.8 String Immutability * Strings are **immutable**, meaning you **cannot change a character** directly. * To modify a string, create a **new string**. ```python text = "Python" # text[0] = "J" # ❌ Error new_text = "J" + text[1:] print(new_text) # Jython ``` --- ### 17.9 Summary * Strings are sequences of characters. * Support **indexing, slicing, concatenation, repetition**. * Provide **many built-in methods** for manipulation. * Are **immutable**, but can be transformed to create new strings. --- ## 18. Type Casting in Python **Type casting** is the process of **converting a value from one data type to another**. Python provides built-in functions to perform type casting. --- ### 18.1 Casting to Integer (`int`) * Converts a value to **integer**. * **Note:** Floats are truncated (decimal part removed). Boolean `True` → `1`, `False` → `0`. Strings must represent a number. ```python # From float to int num = 12.75 print(int(num)) # 12 # From boolean to int b1 = True b2 = False print(int(b1)) # 1 print(int(b2)) # 0 # From string to int s = "50" print(int(s)) # 50 ``` * **Invalid conversion**: ```python s = "hello" # int(s) # ❌ Error, cannot convert non-numeric string ``` --- ### 18.2 Casting to Float (`float`) * Converts a value to **float**. * Boolean `True` → `1.0`, `False` → `0.0`. Strings must represent a number. ```python # From int to float x = 10 print(float(x)) # 10.0 # From boolean to float b = True print(float(b)) # 1.0 # From string to float s = "12.5" print(float(s)) # 12.5 ``` * **Invalid conversion**: ```python s = "Python" # float(s) # ❌ Error ``` --- ### 18.3 Casting to Boolean (`bool`) * Converts a value to **Boolean** (`True` or `False`). * **Falsy values → False:** `0, 0.0, "", [], {}, (), None` * **All other values → True** ```python # From int to bool print(bool(0)) # False print(bool(10)) # True # From float to bool print(bool(0.0)) # False print(bool(3.14)) # True # From string to bool print(bool("")) # False print(bool("Hi")) # True ``` --- ### 18.4 Casting to String (`str`) * Converts a value to **string**. * Can convert int, float, boolean, or other types to a string. ```python # From int to string x = 100 print(str(x)) # "100" # From float to string f = 12.34 print(str(f)) # "12.34" # From boolean to string b = True print(str(b)) # "True" ``` --- ### 18.5 Summary of Type Casting | From Type | To Type | Example | Result | | --------- | ------- | --------------- | ---------- | | float | int | `int(12.7)` | 12 | | boolean | int | `int(True)` | 1 | | string | int | `int("50")` | 50 | | int | float | `float(10)` | 10.0 | | string | float | `float("12.5")` | 12.5 | | int/float | string | `str(100)` | "100" | | any | bool | `bool(value)` | True/False | * **Important Notes:** 1. Strings must represent a valid number to convert to `int` or `float`. 2. Boolean conversion follows Python’s **truthy/falsy rules**. --- ## 19. Non-Primitive Data Types in Python **Non-primitive data types** are used to store **multiple values** or **collections of values**. * Unlike primitive data types, they can hold **more than one item**. * Common non-primitive data types: **List, Tuple, Set, Dictionary**. * Here, we focus on **List** and **Tuple**. --- ### 19.1 List (`list`) * **Definition:** A **list** is an **ordered, mutable collection** of items. * **Usage:** Store multiple values of any type in a single variable. * **Syntax:** `[item1, item2, item3, ...]` #### Creating a List ```python # Non-empty list fruits = ["apple", "banana", "cherry"] # Empty list empty_list = [] print(empty_list) # [] ``` #### Features: 1. **Ordered:** Elements maintain their position. 2. **Mutable:** Can **change, add, or remove items**. 3. **Indexing & Slicing:** Access items by index. ```python fruits = ["apple", "banana", "cherry"] print(fruits[0]) # apple print(fruits[-1]) # cherry print(fruits[0:2]) # ['apple', 'banana'] ``` --- #### 19.1.1 Add Values to a List | Method | Description | Example | | --------------------- | ---------------------------------------- | ----------------------------------- | | `append(item)` | Add an item at the end | `fruits.append("orange")` | | `insert(index, item)` | Insert item at specific index | `fruits.insert(1, "mango")` | | `extend(iterable)` | Add multiple items from another iterable | `fruits.extend(["kiwi", "grapes"])` | ```python fruits = ["apple", "banana"] fruits.append("orange") # ["apple", "banana", "orange"] fruits.insert(1, "mango") # ["apple", "mango", "banana", "orange"] fruits.extend(["kiwi", "grapes"]) # ["apple", "mango", "banana", "orange", "kiwi", "grapes"] ``` --- #### 19.1.2 Remove Values from a List | Method | Description | Example | | -------------- | ----------------------------------- | --------------------------------- | | `remove(item)` | Remove first occurrence of item | `fruits.remove("banana")` | | `pop(index)` | Remove item at index (default last) | `fruits.pop()` or `fruits.pop(1)` | | `clear()` | Remove all items from the list | `fruits.clear()` | ```python fruits = ["apple", "banana", "cherry"] fruits.remove("banana") # ["apple", "cherry"] fruits.pop() # ["apple", "cherry"] → removes last item fruits.clear() # [] ``` --- #### 19.1.3 Other Useful List Methods | Method | Description | Example | | ------------- | --------------------------------- | ------------------------ | | `len(list)` | Returns number of elements | `len(fruits)` | | `sort()` | Sorts the list in ascending order | `numbers.sort()` | | `reverse()` | Reverses the list | `numbers.reverse()` | | `count(item)` | Count occurrences of an item | `fruits.count("apple")` | | `index(item)` | Returns first index of item | `fruits.index("cherry")` | ```python fruits = ["apple", "banana", "apple"] print(len(fruits)) # 3 print(fruits.count("apple")) # 2 print(fruits.index("banana")) # 1 ``` --- ### 19.2 Tuple (`tuple`) * **Definition:** A **tuple** is an **ordered, immutable collection** of items. * **Usage:** Store multiple values that **should not change**. * **Syntax:** `(item1, item2, item3, ...)` #### Creating a Tuple ```python # Non-empty tuple numbers = (1, 2, 3, 4) fruits = ("apple", "banana", "cherry") # Empty tuple empty_tuple = () print(empty_tuple) # () ``` #### Features: 1. **Ordered:** Elements maintain their position. 2. **Immutable:** Cannot **change, add, or remove items** after creation. 3. **Indexing & Slicing:** Access items by index. ```python fruits = ("apple", "banana", "cherry") print(fruits[0]) # apple print(fruits[-1]) # cherry print(fruits[0:2]) # ('apple', 'banana') ``` #### Tuple Operations: * You **cannot** modify items. * You can **concatenate** or **repeat** tuples: ```python t1 = (1, 2) t2 = (3, 4) t3 = t1 + t2 # (1, 2, 3, 4) t4 = t1 * 3 # (1, 2, 1, 2, 1, 2) print(t3) print(t4) ``` #### Tuple Methods: | Method | Description | Example | | ------------- | ---------------------------- | ------------------ | | `len(tuple)` | Returns number of elements | `len(numbers)` | | `count(item)` | Count occurrences of an item | `numbers.count(2)` | | `index(item)` | Returns first index of item | `numbers.index(3)` | --- ### 19.3 Summary | Feature | List (`list`) | Tuple (`tuple`) | | -------- | ---------------- | ---------------- | | Ordered | ✅ Yes | ✅ Yes | | Mutable | ✅ Can change | ❌ Cannot change | | Syntax | `[item1, item2]` | `(item1, item2)` | | Empty | `[]` | `()` | | Use Case | Changing data | Fixed data | * **Lists** are used when **data can change**. * **Tuples** are used when **data should remain constant**. --- ## 20. Set and Dictionary in Python ### 20.1 Set (`set`) * **Definition:** A **set** is an **unordered collection of unique items**. * **Usage:** Store multiple values without duplicates. * **Syntax:** `{item1, item2, item3, ...}` #### Creating a Set ```python # Non-empty set fruits = {"apple", "banana", "cherry"} # Empty set empty_set = set() print(empty_set) # set() ``` #### Features: 1. **Unordered:** No index, elements may appear in any order. 2. **Unique:** Duplicate values are automatically removed. 3. **Mutable:** Items can be added or removed. ```python fruits = {"apple", "banana", "cherry", "apple"} print(fruits) # {'apple', 'banana', 'cherry'} → duplicates removed ``` #### 20.1.1 Add Values | Method | Description | Example | | ------------------ | ------------------ | ----------------------------------- | | `add(item)` | Add single item | `fruits.add("orange")` | | `update(iterable)` | Add multiple items | `fruits.update(["kiwi", "grapes"])` | #### 20.1.2 Remove Values | Method | Description | Example | | --------------- | ---------------------------------- | ------------------------- | | `remove(item)` | Remove item, error if not found | `fruits.remove("banana")` | | `discard(item)` | Remove item, no error if not found | `fruits.discard("mango")` | | `pop()` | Remove arbitrary item | `fruits.pop()` | | `clear()` | Remove all items | `fruits.clear()` | #### 20.1.3 Other Useful Operations ```python # Set operations A = {1, 2, 3} B = {3, 4, 5} print(A.union(B)) # {1, 2, 3, 4, 5} print(A.intersection(B)) # {3} print(A.difference(B)) # {1, 2} print(A.symmetric_difference(B)) # {1, 2, 4, 5} ``` --- ### 20.2 Dictionary (`dict`) * **Definition:** A **dictionary** is an **unordered collection of key-value pairs**. * **Usage:** Store data where each value is accessed by a **unique key**. * **Syntax:** `{key1: value1, key2: value2, ...}` #### Creating a Dictionary ```python # Non-empty dictionary person = {"name": "Ram", "age": 30, "city": "Kathmandu"} # Empty dictionary empty_dict = {} print(empty_dict) # {} ``` #### Features: 1. **Unordered:** Items have no fixed order (Python 3.7+ maintains insertion order). 2. **Keys Unique:** Keys must be unique, values can repeat. 3. **Mutable:** Keys and values can be changed. #### 20.2.1 Accessing Values ```python print(person["name"]) # Ram print(person.get("age")) # 30 ``` #### 20.2.2 Add/Update Values ```python person["profession"] = "Engineer" # Add new key-value person["age"] = 31 # Update value ``` #### 20.2.3 Remove Values | Method | Description | Example | | ----------- | ------------------------- | -------------------- | | `pop(key)` | Remove key-value by key | `person.pop("city")` | | `popitem()` | Remove last inserted item | `person.popitem()` | | `clear()` | Remove all items | `person.clear()` | #### 20.2.4 Other Useful Methods | Method | Description | Example | | ---------- | ----------------------- | ----------------- | | `keys()` | Get all keys | `person.keys()` | | `values()` | Get all values | `person.values()` | | `items()` | Get all key-value pairs | `person.items()` | ```python print(person.keys()) # dict_keys(['name', 'age', 'profession']) print(person.values()) # dict_values(['Ram', 31, 'Engineer']) print(person.items()) # dict_items([('name', 'Ram'), ('age', 31), ('profession', 'Engineer')]) ``` --- ### 20.3 Summary | Feature | Set (`set`) | Dictionary (`dict`) | | ------------ | ----------------- | ---------------------------------- | | Ordered | ❌ Unordered | ❌ Unordered (3.7+ insertion order) | | Mutable | ✅ Can change | ✅ Can change | | Unique Items | ✅ Yes | Keys ✅, Values ❌ | | Indexing | ❌ No | ❌ No, use keys | | Empty | `set()` | `{}` | | Use Case | Unique collection | Key-value mapping | * **Sets** are used for **unique items and mathematical operations**. * **Dictionaries** are used for **storing data with key-value relationships**. --- ## 21. Conditional Statements in Python Conditional statements allow your program to **execute different code blocks based on certain conditions**. They are used to make **decisions** in Python. --- ### 21.1 `if` Statement * Executes a block of code **only if a condition is True**. * **Syntax:** ```python if condition: # code to execute if condition is True ``` **Example:** ```python age = 18 if age >= 18: print("You are eligible to vote") ``` *Output:* ``` You are eligible to vote ``` --- ### 21.2 `if-else` Statement * Executes **one block if the condition is True**, and **another block if False**. * **Syntax:** ```python if condition: # code if True else: # code if False ``` **Example:** ```python age = 16 if age >= 18: print("Eligible to vote") else: print("Not eligible to vote") ``` *Output:* ``` Not eligible to vote ``` --- ### 21.3 `if-elif-else` Statement * Used when there are **multiple conditions**. * **Syntax:** ```python if condition1: # code if condition1 is True elif condition2: # code if condition2 is True else: # code if all conditions are False ``` **Example:** ```python marks = 85 if marks >= 90: print("Grade A") elif marks >= 75: print("Grade B") elif marks >= 50: print("Grade C") else: print("Fail") ``` *Output:* ``` Grade B ``` --- ### 21.4 Nested `if` Statements * An `if` or `if-else` statement **inside another `if` statement**. * Used for **more complex decisions**. **Example:** ```python age = 20 citizenship = "Nepal" if age >= 18: if citizenship == "Nepal": print("Eligible to vote") else: print("Not eligible due to citizenship") else: print("Not eligible due to age") ``` *Output:* ``` Eligible to vote ``` --- ### 21.5 Short-Hand (Ternary) `if` * A **compact way** to write `if-else` in a single line. * **Syntax:** ```python value_if_true if condition else value_if_false ``` **Example:** ```python age = 18 status = "Eligible" if age >= 18 else "Not Eligible" print(status) ``` *Output:* ``` Eligible ``` --- ### 21.6 `pass` Statement * `pass` is a **placeholder statement** that does **nothing**. * Used when a statement is syntactically required but you don’t want any action. **Example:** ```python age = 18 if age >= 18: pass # Will do nothing for now else: print("Not eligible") ``` *Output:* *(No output because `pass` does nothing)* * Commonly used in: * Empty functions * Empty loops * Empty condition blocks ```python def my_function(): pass # Function not implemented yet ``` --- ### 21.7 Comparison Operators Used in Conditionals * `==` → equal * `!=` → not equal * `>` → greater than * `<` → less than * `>=` → greater or equal * `<=` → less or equal --- ### 21.8 Logical Operators in Conditionals * **`and`** → True if **both conditions** are True * **`or`** → True if **at least one condition** is True * **`not`** → Inverts the condition **Example:** ```python age = 20 citizenship = "Nepal" if age >= 18 and citizenship == "Nepal": print("Eligible to vote") ``` --- ### 21.9 Summary | Statement Type | Use Case | | -------------- | ------------------------------------------ | | `if` | Execute code if a single condition is True | | `if-else` | Choose between two paths | | `if-elif-else` | Multiple conditions | | Nested `if` | Complex conditions with sub-conditions | | Ternary `if` | Short-hand `if-else` in one line | | `pass` | Placeholder for empty blocks | * Conditional statements allow your program to **make decisions** and **control flow**. * Logical and comparison operators are used **inside the condition** to evaluate True/False. --- ## 22. Loops in Python Loops are used to **execute a block of code repeatedly** until a certain condition is met. They help **automate repetitive tasks** and **reduce code duplication**. --- ### 22.1 Introduction to Loops * Loops **repeat code** multiple times based on a **condition** or **sequence**. * Two main types in Python: 1. **`for` loop** – iterates over a sequence (like list, tuple, string). 2. **`while` loop** – executes as long as a condition is True. * Optional **loop control statements**: * `break` → exit the loop immediately * `continue` → skip the current iteration and continue * `pass` → placeholder that does nothing --- ### 22.2 `for` Loop * Used to **iterate over a sequence** (list, tuple, string, range, etc.). * **Syntax:** ```python for variable in sequence: # code to execute ``` **Example 1 – Iterating over a list:** ```python fruits = ["apple", "banana", "cherry"] for fruit in fruits: print(fruit) ``` *Output:* ``` apple banana cherry ``` **Example 2 – Using `range()`:** ```python for i in range(5): # 0 to 4 print(i) ``` *Output:* ``` 0 1 2 3 4 ``` **Example 3 – Iterating over a string:** ```python for letter in "Python": print(letter) ``` --- ### 22.3 `while` Loop * Repeats a block of code **as long as a condition is True**. * **Syntax:** ```python while condition: # code to execute ``` **Example:** ```python count = 0 while count < 5: print(count) count += 1 ``` *Output:* ``` 0 1 2 3 4 ``` --- ### 22.4 Nested Loops * **Loop inside another loop**. * Can be used with `for` or `while`. **Example – Nested `for` loop:** ```python for i in range(1, 4): for j in range(1, 4): print(i, j) ``` *Output:* ``` 1 1 1 2 1 3 2 1 2 2 2 3 3 1 3 2 3 3 ``` --- ### 22.5 Loop Control Statements #### 22.5.1 `break` * **Exits the loop immediately**, even if the condition is True. ```python for i in range(5): if i == 3: break print(i) ``` *Output:* ``` 0 1 2 ``` #### 22.5.2 `continue` * **Skips the current iteration** and moves to the next iteration. ```python for i in range(5): if i == 3: continue print(i) ``` *Output:* ``` 0 1 2 4 ``` #### 22.5.3 `pass` * **Placeholder statement**; does nothing. * Useful in **empty loops**. ```python for i in range(5): if i < 3: pass else: print(i) ``` *Output:* ``` 3 4 ``` --- ### 22.6 `else` with Loops * Python allows an optional **`else` block** with loops. * Executes **only if the loop completes normally** (no `break`). **Example:** ```python for i in range(3): print(i) else: print("Loop finished without break") ``` *Output:* ``` 0 1 2 Loop finished without break ``` **Example with `break`:** ```python for i in range(3): if i == 1: break print(i) else: print("Loop finished without break") ``` *Output:* ``` 0 ``` *(The `else` block is skipped because of `break`.)* --- ### 22.7 Summary | Loop Type | Use Case | Key Points | | ---------------- | ---------------------------------- | ------------------------------------- | | `for` | Iterate over sequence | Works with list, tuple, string, range | | `while` | Repeat until condition is False | Condition-controlled loop | | Nested Loops | Loop inside loop | Can combine `for` and `while` | | `break` | Exit loop immediately | Stops the loop | | `continue` | Skip current iteration | Moves to next iteration | | `pass` | Placeholder | Does nothing, useful in empty blocks | | `else` with loop | Executes if loop finishes normally | Skipped if `break` occurs | * Loops are essential for **automation, repetition, and complex logic** in Python. --- ## 23. Functions in Python A **function** is a **block of reusable code** that performs a **specific task**. Functions help to: * Avoid code repetition * Organize code into **logical blocks** * Make code **readable and maintainable** --- ### 23.1 Introduction to Functions * Functions can **take inputs (parameters)** and **return outputs (values)**. * **Syntax of a function:** ```python def function_name(parameters): """ Optional docstring to describe the function """ # code block return value # optional ``` **Example – Simple Function:** ```python def greet(): print("Hello, World!") greet() # Call the function ``` *Output:* ``` Hello, World! ``` --- ### 23.2 Function Parameters (Arguments) Functions can accept **data from the caller** using parameters. #### 23.2.1 Positional Arguments * Values are assigned **based on the order** of parameters. ```python def greet(name, age): print(f"Hello {name}, you are {age} years old") greet("Ram", 30) # name="Ram", age=30 ``` --- #### 23.2.2 Keyword Arguments * Values are assigned **using parameter names**, order does not matter. ```python greet(age=30, name="Ram") ``` *Output:* ``` Hello Ram, you are 30 years old ``` --- #### 23.2.3 Default Arguments * Assign **default values** to parameters. * Used when the caller **does not provide a value**. ```python def greet(name="Guest"): print(f"Hello {name}") greet() # Uses default value greet("Ram") # Overrides default value ``` *Output:* ``` Hello Guest Hello Ram ``` --- #### 23.2.4 Variable-Length Arguments * Sometimes we do not know **how many arguments will be passed**. * Python provides: * **`*args`** → accepts multiple **positional arguments** as a tuple * **`**kwargs`** → accepts multiple **keyword arguments** as a dictionary **Example – `*args`:** ```python def add_numbers(*args): return sum(args) print(add_numbers(1, 2, 3, 4)) # 10 ``` **Example – `**kwargs`:** ```python def print_info(**kwargs): for key, value in kwargs.items(): print(f"{key}: {value}") print_info(name="Ram", age=30, city="Kathmandu") ``` *Output:* ``` name: Ram age: 30 city: Kathmandu ``` --- ### 23.3 Return Statement * Functions can **return values** to the caller using `return`. * If no return is used, function returns **`None`**. ```python def add(a, b): return a + b result = add(5, 3) print(result) # 8 ``` --- ### 23.4 Anonymous Functions (`lambda`) * Small **single-expression functions**. * Syntax: `lambda parameters: expression` ```python square = lambda x: x**2 print(square(5)) # 25 ``` * Often used with `map()`, `filter()`, and `reduce()`. --- ### 23.5 Scope of Variables * **Local variables:** Defined inside a function; accessible **only inside**. * **Global variables:** Defined outside; accessible **anywhere**. ```python x = 10 # global def func(): y = 5 # local print(x, y) func() print(x) # 10 # print(y) -> Error, y is local ``` --- ### 23.6 Summary | Concept | Description | | ------------------------- | ---------------------------------------------- | | Function Definition | `def function_name(parameters):` | | Positional Arguments | Assigned based on order | | Keyword Arguments | Assigned using parameter names | | Default Arguments | Parameters with default values | | Variable-Length Arguments | `*args` for positional, `**kwargs` for keyword | | Return Statement | Sends value back to caller | | Anonymous Function | `lambda` for single-expression functions | | Scope | Local vs Global variables | * Functions **improve code reusability, readability, and maintainability**. --- ## 24. Exception Handling in Python (`try-except`) In Python, **errors** that occur during program execution are called **exceptions**. Without handling, exceptions **stop the program abruptly**. Exception handling allows the program to **continue running safely**. --- ### 24.1 Types of Errors in Python 1. **Syntax Error** * Occurs when Python **cannot understand the code** due to incorrect syntax. * Example: ```python if True print("Hello") ``` *Output:* ``` SyntaxError: expected ':' ``` * **Note:** Syntax errors are **detected before program execution**. 2. **Logical Error** * Occurs when the program runs **without crashing**, but the **output is incorrect**. * Example: ```python x = 10 y = 5 result = x - y # Intended to add print(result) ``` *Output:* ``` 5 ``` * **Note:** Logical errors **do not raise exceptions**; careful debugging is needed. 3. **Runtime Error (Exceptions)** * Occurs **during program execution** when Python encounters an unexpected situation. * Example: ```python x = 10 / 0 ``` *Output:* ``` ZeroDivisionError: division by zero ``` --- ### 24.2 Introduction to `try-except` * **Exceptions** are handled using `try` and `except` blocks. * Allows **graceful error handling** without crashing the program. **Basic Syntax:** ```python try: # Code that may raise an exception except: # Code to handle the exception ``` **Example:** ```python try: x = 10 / 0 except: print("Error occurred: Division by zero") ``` --- ### 24.3 Catching Specific Exceptions ```python try: x = int("abc") except ValueError: print("Invalid input!") ``` * You can catch **multiple exception types**: ```python try: num = int(input("Enter a number: ")) result = 10 / num except (ValueError, ZeroDivisionError) as e: print("An error occurred:", e) ``` --- ### 24.4 Catching Multiple Exceptions in One Line * Python allows **grouping multiple exception types** in one `except` block. ```python try: num = int(input("Enter a number: ")) result = 10 / num except (ValueError, ZeroDivisionError) as e: print("Error:", e) ``` --- ### 24.5 `else` Block * Executes **only if no exception occurs**. ```python try: result = 10 / 2 except ZeroDivisionError: print("Cannot divide by zero") else: print("Result is:", result) ``` --- ### 24.6 `finally` Block * Executes **always**, even if an exception occurs. * Commonly used to **release resources**. ```python try: f = open("data.txt") content = f.read() except FileNotFoundError: print("File not found") finally: print("This always executes") try: f.close() except: pass ``` --- ### 24.7 Raising Exceptions (`raise`) * You can **manually raise exceptions** using `raise`. ```python def divide(a, b): if b == 0: raise ValueError("Cannot divide by zero") return a / b try: result = divide(10, 0) except ValueError as e: print("Error:", e) ``` --- ### 24.8 Error Chaining (`from` keyword) * Python allows **exception chaining**, where one exception is **raised from another**. * Useful for debugging and understanding the **root cause of exceptions**. ```python try: x = int("abc") except ValueError as e: raise RuntimeError("Failed to convert input") from e ``` *Output:* ``` Traceback (most recent call last): File "<stdin>", line 2, in <module> ValueError: invalid literal for int() with base 10: 'abc' The above exception was the direct cause of the following exception: RuntimeError: Failed to convert input ``` --- ### 24.9 Common Built-in Exceptions | Exception Type | Description | | ------------------- | ------------------------------- | | `ZeroDivisionError` | Division by zero | | `ValueError` | Invalid value conversion | | `TypeError` | Wrong type operation | | `IndexError` | Invalid index | | `KeyError` | Invalid dictionary key | | `FileNotFoundError` | File not found | | `ImportError` | Module not found | | `AttributeError` | Invalid object attribute access | --- ### 24.10 Best Practices 1. Catch **specific exceptions** instead of generic `except:`. 2. Use `finally` to **release resources**. 3. Avoid using exceptions for **normal flow control**. 4. Use `as` to **inspect the exception object**. 5. Use **error chaining** (`from`) to track the original cause of exceptions. 6. Always **debug logical errors** carefully; they don’t raise exceptions. --- ### 24.11 Full Example with `else` and `finally` ```python try: num = int(input("Enter a number: ")) result = 10 / num except ValueError: print("Please enter a valid number") except ZeroDivisionError: print("Cannot divide by zero") else: print("Result is:", result) finally: print("Execution completed") ``` *Sample Input:* `0` *Output:* ``` Cannot divide by zero Execution completed ``` *Sample Input:* `5` *Output:* ``` Result is: 2.0 Execution completed ``` --- ### 24.12 Summary | Keyword/Concept | Purpose | | --------------- | ------------------------------------------- | | `try` | Wrap code that may throw exceptions | | `except` | Handle exceptions | | `else` | Executes if no exception occurs | | `finally` | Executes always, used for cleanup | | `raise` | Manually raise an exception | | `from` | Chain exceptions to show the original cause | | Syntax Error | Code violates Python syntax | | Logical Error | Code runs but produces wrong output | | Runtime Error | Error occurs during program execution | * Python errors can be **syntax, logical, or runtime**. * `try-except` ensures **program continues execution** even in case of runtime errors. * Error chaining helps in **debugging complex programs**. --- ## 25. File Handling in Python File handling allows Python programs to **store data permanently** and **read/write external files**. Files can be **text files** or **binary files**. --- ### 25.1 Introduction * Files are used to **store data outside the program**. * Python provides built-in functions to **open, read, write, and close files**. * **Basic workflow:** 1. Open a file 2. Perform operations (read/write) 3. Close the file --- ### 25.2 Opening a File * **`open()`** is used to open a file. * **Syntax:** ```python file_object = open(filename, mode) ``` **Modes:** | Mode | Description | | ------ | ------------------------------------------------ | | `'r'` | Read (default). File must exist | | `'w'` | Write. Creates a new file or overwrites existing | | `'a'` | Append. Adds content to end of file | | `'x'` | Create a new file. Fails if file exists | | `'rb'` | Read binary | | `'wb'` | Write binary | | `'ab'` | Append binary | | `'r+'` | Read and write | | `'w+'` | Write and read (overwrite) | | `'a+'` | Append and read | **Example:** ```python f = open("example.txt", "r") # open in read mode ``` --- ### 25.3 Closing a File * **`close()`** releases the file resources. ```python f = open("example.txt", "r") f.close() ``` * **Best practice:** Use **context manager** to automatically close files. --- ### 25.4 Context Manager (`with` keyword) * Automatically **opens and closes** files, even if errors occur. ```python with open("example.txt", "r") as f: content = f.read() print(content) # No need to call f.close() ``` --- ### 25.5 Reading Files * **`read()`** → Reads the whole file as a string * **`read(size)`** → Reads `size` number of characters * **`readline()`** → Reads one line at a time * **`readlines()`** → Reads all lines as a list **Example:** ```python with open("example.txt", "r") as f: content = f.read() print(content) ``` **Example – Reading line by line:** ```python with open("example.txt", "r") as f: for line in f: print(line.strip()) ``` --- ### 25.6 Writing Files * **`write()`** → Writes a string to the file * **`writelines()`** → Writes a list of strings **Example – Writing a file:** ```python with open("example.txt", "w") as f: f.write("Hello, World!\n") f.write("Welcome to Python file handling.\n") ``` **Example – Appending:** ```python with open("example.txt", "a") as f: f.write("Appending new line.\n") ``` --- ### 25.7 File Pointer & `seek()` * The **file pointer** indicates the current position in the file. * **`seek(offset, whence)`** moves the pointer. * `offset` → number of bytes to move * `whence` → reference position (0=start, 1=current, 2=end) ```python with open("example.txt", "r") as f: print(f.read(5)) # reads first 5 chars f.seek(0) # move pointer to beginning print(f.read(5)) ``` --- ### 25.8 Deleting a File * Use **`os` module**: ```python import os os.remove("example.txt") # Deletes file ``` --- ### 25.9 Exception Handling in File Operations * Use `try-except` to **handle file-related errors**. ```python try: with open("missing.txt", "r") as f: content = f.read() except FileNotFoundError: print("File not found!") except IOError: print("Error reading/writing the file") finally: print("File operation attempted") ``` --- ### 25.10 Common File Handling Keywords | Keyword | Purpose | | ------------ | ------------------------------------------- | | `open` | Opens a file | | `close` | Closes a file | | `with` | Context manager for automatic file handling | | `read` | Reads content from file | | `readline` | Reads one line at a time | | `readlines` | Reads all lines into a list | | `write` | Writes string to file | | `writelines` | Writes list of strings to file | | `seek` | Moves file pointer | | `os.remove` | Deletes a file | --- ### 25.11 File Handling Examples **Example 1 – Read & Print File** ```python with open("data.txt", "r") as file: print(file.read()) ``` **Example 2 – Write & Append** ```python with open("data.txt", "w") as file: file.write("Line 1\n") with open("data.txt", "a") as file: file.write("Line 2\n") ``` **Example 3 – Read lines as list** ```python with open("data.txt", "r") as file: lines = file.readlines() for line in lines: print(line.strip()) ``` **Example 4 – Handle missing file** ```python try: with open("missing.txt", "r") as f: print(f.read()) except FileNotFoundError: print("File not found!") ``` --- ### 25.12 Summary | Concept | Purpose | | ------------------------------------- | ----------------------------------------- | | `open(filename, mode)` | Open a file | | `close()` | Close the file | | `with` | Automatically manage file opening/closing | | File modes (`r`, `w`, `a`) | Read, write, append | | `read()`, `readline()`, `readlines()` | Read content | | `write()`, `writelines()` | Write content | | `seek()` | Move file pointer | | `os.remove()` | Delete file | | Exception handling | Gracefully handle file errors | * File handling is essential for **data storage, reading logs, and working with external files**. * Using **context managers and exception handling** ensures **safe and clean file operations**. --- ## 26. Python Classes, Objects, Variables, Methods, and Four Pillars of OOP Python is an **object-oriented programming (OOP)** language. **Classes** and **objects** are the core concepts of OOP in Python, and the **Four Pillars of OOP** ensure **code reusability, modularity, and maintainability**. --- ### 26.1 Introduction * **Class:** Blueprint or template for creating objects. * **Object:** Instance of a class. * Classes help **organize code** and **model real-world entities**. **Syntax of a class:** ```python class ClassName: # class attributes # methods ``` **Creating an object:** ```python object_name = ClassName() ``` --- ### 26.2 Constructor (`__init__`) * Special method automatically called when an **object is created**. * Used to initialize **instance attributes**. ```python class Person: def __init__(self, name, age): self.name = name self.age = age p1 = Person("Ram", 30) print(p1.name, p1.age) ``` --- ### 26.3 The `self` Keyword * Refers to the **current instance** of the class. * Used to **access instance attributes and methods**. ```python class Person: def __init__(self, name): self.name = name def greet(self): # instance method print(f"Hello, my name is {self.name}") p1 = Person("Ram") p1.greet() ``` --- ### 26.4 Types of Variables in Classes 1. **Instance Variables** – Unique to each object 2. **Class (Static) Variables** – Shared by all objects 3. **Public Variables** – Accessible anywhere 4. **Private Variables** – Accessible only via getter/setter methods ```python class Person: species = "Human" # class variable def __init__(self, name, age): self.name = name # instance/public variable self.__age = age # private variable # Instance method def greet(self): print(f"Hello, my name is {self.name} and I am {self.__age}") # Getter for private variable def get_age(self): return self.__age ``` --- ### 26.5 Methods in Classes 1. **Instance Methods** – Operate on instance variables 2. **Class Methods** – Operate on class variables (`@classmethod`) 3. **Static Methods** – Independent utility methods (`@staticmethod`) ```python class Math: @staticmethod def add(a, b): return a + b class Person: species = "Human" @classmethod def show_species(cls): print(f"Species: {cls.species}") ``` --- ### 26.6 Inheritance * Allows a **class to inherit attributes and methods from another class**. * **Parent class (superclass)** → Base class * **Child class (subclass)** → Derived class ```python class Student(Person): def study(self): print(f"{self.name} is studying") ``` **Types of Inheritance:** * Single Inheritance * Multilevel Inheritance * Multiple Inheritance --- ### 26.7 Encapsulation * Hiding internal details using **private variables** (`__`). * Access using **getter and setter methods**. --- ### 26.8 Polymorphism * **Same method name, different behavior** via method overriding. * Includes **operator overloading**. ```python class Animal: def sound(self): print("Some sound") class Dog(Animal): def sound(self): print("Bark") ``` --- ### 27. Four Pillars of OOP | Pillar | Purpose | Example | | ----------------- | ---------------------------------- | ---------------------------------------- | | **Encapsulation** | Hide internal data | Private variable + getter/setter | | **Abstraction** | Hide implementation | Abstract class & methods | | **Inheritance** | Reuse code | Child class inherits parent class | | **Polymorphism** | Same interface, different behavior | Method overriding / operator overloading | --- ### 27.1 Abstraction * **Definition:** Hiding complex implementation and exposing only necessary details. * Achieved using **abstract classes** (`abc` module). ```python from abc import ABC, abstractmethod class Shape(ABC): @abstractmethod def area(self): pass class Rectangle(Shape): def __init__(self, width, height): self.width = width self.height = height def area(self): return self.width * self.height r = Rectangle(5, 10) print(r.area()) # 50 ``` --- ### 26.9 Keywords Related to Classes | Keyword / Concept | Purpose | | ----------------- | -------------------------------------- | | `class` | Define a class | | `__init__` | Constructor for object initialization | | `self` | Refers to current instance | | `@classmethod` | Define class method | | `@staticmethod` | Define static method | | `super()` | Access parent class methods/attributes | | `_variable` | Protected attribute (convention) | | `__variable` | Private attribute | | `pass` | Placeholder for empty class or method | --- ### 26.10 Complete Example ```python from abc import ABC, abstractmethod class Person: species = "Human" # class variable def __init__(self, name, age): self.name = name # instance variable self.__age = age # private variable def greet(self): # instance method print(f"Hello, my name is {self.name} and I am {self.__age}") def get_age(self): # getter for private variable return self.__age @classmethod def show_species(cls): # class method print(f"Species: {cls.species}") @staticmethod def welcome(): # static method print("Welcome to Python classes") class Student(Person): def study(self): print(f"{self.name} is studying") class Shape(ABC): @abstractmethod def area(self): pass class Rectangle(Shape): def __init__(self, w, h): self.w = w self.h = h def area(self): return self.w * self.h # Usage p1 = Person("Ram", 30) p1.greet() print("Age via getter:", p1.get_age()) Person.show_species() Person.welcome() s1 = Student("Hari", 25) s1.greet() s1.study() r = Rectangle(5, 10) print("Area:", r.area()) ``` --- ### 26.11 Summary | Concept | Description | | ------------------------------------------------ | ----------------------------------------- | | Class | Blueprint for objects | | Object | Instance of a class | | Constructor (`__init__`) | Initializes instance attributes | | `self` | Refers to instance | | Instance variable | Unique to each object | | Class (static) variable | Shared by all objects | | Public variable | Accessible anywhere | | Private variable | Accessible only via getter/setter | | Instance method | Operates on instance attributes | | Class methods | Operates on class attributes | | Static methods | Independent utility methods | | Inheritance | Child class inherits parent class | | Encapsulation | Hiding data using private attributes | | Abstraction | Hiding implementation, exposing interface | | Polymorphism | Method overriding / operator overloading | | Keywords (`class`, `self`, `@classmethod`, etc.) | Define and manage classes | --- ![OOP](https://hackmd.io/_uploads/H1W-QuJFgx.png)