From 43d2b099453929cd0ab0b335090f74d5c6f2eb0f Mon Sep 17 00:00:00 2001 From: Hammad2 Date: Sun, 27 Apr 2025 09:23:50 +0500 Subject: [PATCH 1/2] Update readme.md --- .../01_introduction_to_python/readme.md | 281 +++++++++++++++++- 1 file changed, 280 insertions(+), 1 deletion(-) diff --git a/00_python_colab/01_introduction_to_python/readme.md b/00_python_colab/01_introduction_to_python/readme.md index 4732076..00da1ff 100644 --- a/00_python_colab/01_introduction_to_python/readme.md +++ b/00_python_colab/01_introduction_to_python/readme.md @@ -1 +1,280 @@ -# [Lesson 01: Introduction to Python](https://colab.research.google.com/drive/1LqRMqVAff7jR_Xha7arxwHkFdQL08xAu?usp=sharing) +## πŸ“Œ Summary + +This document covers essential Python concepts β€” from basics to how Python handles your code internally β€” with simple explanations, real-world examples, and best practices. + +--- + +## πŸ”— Useful Links + +- [Download Python](https://www.python.org/downloads/) +- [Python 3.13.2 Documentation](https://docs.python.org/3/) +- [W3Schools.com – Python Tutorial](https://www.w3schools.com/python/) +- [Tutorialspoint.com – Python Programming](https://www.tutorialspoint.com/python/index.htm) +- [Visual Studio Code (VS Code)](https://code.visualstudio.com/) +- [Cursor IDE](https://cursor.sh/) + +--- + +## 🐍 What is Python? + +- Python is a **high-level**, **interpreted**, and **simple-to-read** programming language. +- Created by **Guido van Rossum**. +- Supports multiple programming styles: + - Procedural + - Object-Oriented + - Functional +- Huge library support and strong global community. +- Works on **Windows, Mac, and Linux**. +- Used for: + - Web development + - Data analysis + - AI and machine learning + - Automation + - Much more! + +βœ… Python is **easy** to learn and **extremely popular** worldwide. + +--- + +## πŸ€– Python in Agentic AI (Self-Acting AI) + +Python plays a huge role in building **autonomous AI agents** (systems that think, decide, and act). + +### Tools it supports: +- LangChain +- CrewAI +- Microsoft AutoGen +- Auto-GPT +- OpenAI APIs + +### Common AI tasks: +- Natural Language Processing (NLP) +- Reinforcement Learning +- Intelligent Automation + +βœ… Python helps AI systems **interact, learn, and adapt**! + +--- + +## πŸ› οΈ Practical Applications of Python + +Python is used for: + +- **Data Science**: Data analysis, machine learning, visualization +- **Agentic AI**: Smart agents, chatbots, digital assistants +- **Machine Learning**: Predictive models, recommendation systems +- **Natural Language Processing (NLP)**: Text analysis, translation +- **Computer Vision**: Image and face recognition +- **Robotics**: Controlling drones and robots +- **Web Development**: Websites, APIs +- **AI & Deep Learning**: Neural networks, deep learning apps +- **Automation**: Scripts that save time +- **Scientific Computing**: Simulations, experiments +- **Cybersecurity**: Penetration testing +- **IoT (Internet of Things)**: Smart device programming + +βœ… Python is everywhere! + +--- + +## 🧠 Python's Role in Agentic AI + +- Python’s **simplicity** + **huge library support** = perfect combination for building intelligent, self-learning systems. + +βœ… It empowers developers to build **self-adapting**, **autonomous** agents. + +--- + +## πŸ–₯️ Code Execution Journey + +Here’s how Python code travels: + +```text +Source Code ➑️ Bytecode ➑️ Runtime Execution ➑️ Output +``` + +βœ… It’s like a **chain reaction** β€” from writing to seeing the results! + +--- + +## 🧩 What is Python Bytecode? + +- After writing Python code, it **compiles into bytecode** (special low-level instructions). +- Then, the Python Interpreter executes this bytecode. + +βœ… **Bytecode is platform-independent**, meaning it can run anywhere Python is installed! + +--- + +## πŸ” How Python Compiles Code + +1. **Lexical Analysis**: Breaks your code into pieces (tokens). +2. **Syntax Analysis**: Checks the structure. +3. **Semantic Analysis**: Ensures logical sense. +4. **Bytecode Generation**: Creates bytecode instructions. + +--- + +## 🧾 Example: Python Code and Bytecode + +```python +class Person: + def __init__(self, name: str, age: int): + self.name = name + self.age = age + + def greet(self): + print(f"Hello, my name is {self.name} and I am {self.age} years old.") + +person = Person("Arif Rozani", 20) +person.greet() +``` + +βœ… Behind the scenes, Python **translates** this into **bytecode**! + +--- + +## πŸ” Seeing Bytecode Using `dis` Module + +```python +import dis +dis.dis(Person) +``` + +βœ… `dis` shows the **low-level steps** your code follows, like the **__init__** and **greet** methods. + +--- + +## 🧠 Why is Python Bytecode Important? + +- **Platform Independent**: Runs anywhere. +- **Dynamic Typing**: Types decided at runtime. +- **Flexibility**: Easy code updates and changes. + +βœ… Bytecode makes Python powerful and easy to run! + +--- + +## βš™οΈ How Python Uses Bytecode + +| Step | Description | +|:---|:---| +| Compilation | Python compiles `.py` to `.pyc` bytecode | +| Execution | Python Virtual Machine (PVM) runs bytecode | +| Caching | Saves compiled bytecode in `__pycache__` for faster loading | + +--- + +## πŸ“‚ Can Bytecode Run on Any OS? + +βœ… Yes! +But you must have: + +- The correct **Python version** installed. +- (.pyc files aren't backward compatible, e.g., 3.10 ➑️ 3.8 won't work.) + +--- + +## πŸš€ Can You Run Bytecode Directly? + +❌ No. +You **still need the Python interpreter** (like **CPython**) to run `.pyc` files. + +βœ… Different from Java bytecode which runs inside a JVM. + +--- + +## πŸ› οΈ How to Run Bytecode Manually + +### 1. Compile Python file + +```bash +python -m compileall TestP.py +``` + +βœ… Creates a `.pyc` file inside a `__pycache__` folder. + +--- + +### 2. Run Bytecode + +Navigate into `__pycache__` and run: + +```bash +python TestP.cpython-312.pyc +``` + +βœ… You are now running **compiled bytecode**! + +--- + +## πŸ“ Indentation in Python + +### What is Indentation? + +- **Spaces or tabs** at the start of a line. +- Groups lines into **blocks** of code. + +--- + +### Why is Indentation Important? + +- Defines **structure**. +- Prevents **errors**. +- Makes code **readable**. + +--- + +### Rules of Indentation + +- Use **only spaces** or **only tabs** (never mix). +- Standard: **4 spaces** per level. +- After a colon `:`, always indent the next line. +- Inside functions, loops, classes β€” **always indent**. + +--- + +### Examples + +βœ… Correct: + +```python +if True: + print("Hello") + print("World") +``` + +❌ Incorrect: + +```python +if True: +print("Hello") + print("World") +``` + +βœ… Correct Function: + +```python +def greet(name: str): + print("Hello, " + name + "!") +``` + +--- + +## πŸ“‹ Best Practices for Indentation + +- Use editors like **VS Code** or **Cursor** with **auto-indentation**. +- Prefer **spaces** over **tabs**. +- Stay **consistent** across your project. + +--- + +## πŸ“ Exercise + +βœ… Write a simple Python program using correct indentation: + +```python +if True: + print("This is indented properly!") +``` + From d73f509797064c43f420a163f2e3ee9f8ed3f1c3 Mon Sep 17 00:00:00 2001 From: Hammad2 Date: Sun, 27 Apr 2025 13:33:33 +0500 Subject: [PATCH 2/2] added summary for each topics --- 00_python_colab/02_data_types/readme.md | 374 +++++++++++++++++- .../03_operators_keywords_variables/readme.md | 298 +++++++++++++- 00_python_colab/04_strings_casting/readme.md | 308 ++++++++++++++- 00_python_colab/05_control_flow/readme.md | 363 ++++++++++++++++- .../06_lists_tuples_dict/readme.md | 248 +++++++++++- 00_python_colab/07_sets/readme.md | 220 ++++++++++- .../08_modules_functions/readme.md | 263 +++++++++++- .../09_exception_handling/readme.md | 291 +++++++++++++- 8 files changed, 2357 insertions(+), 8 deletions(-) diff --git a/00_python_colab/02_data_types/readme.md b/00_python_colab/02_data_types/readme.md index aacd394..f46e124 100644 --- a/00_python_colab/02_data_types/readme.md +++ b/00_python_colab/02_data_types/readme.md @@ -1 +1,373 @@ -# [Lesson 02: Data Types](https://colab.research.google.com/drive/1gNQDG1m7_cf-cY5cm_tmYNKDuwD9RneN?usp=sharing) +## Overview + +This repository contains a comprehensive summary of Python's fundamental data types, explained in a beginner-friendly manner. The guide uses simple analogies and practical examples to make complex concepts accessible to new programmers. + +## Table of Contents + +- [Numeric Types](#numeric-types) + - [Integer (int)](#integer-int) + - [Floating-Point (float)](#floating-point-float) + - [Complex (complex)](#complex-complex) +- [Boolean (bool)](#boolean-bool) +- [Sequence Types](#sequence-types) + - [String (str)](#string-str) + - [List (list)](#list-list) + - [Tuple (tuple)](#tuple-tuple) + - [Range (range)](#range-range) +- [Set Types](#set-types) + - [Set (set)](#set-set) + - [Frozen Set (frozenset)](#frozen-set-frozenset) +- [Mapping Type](#mapping-type) + - [Dictionary (dict)](#dictionary-dict) +- [Binary Types](#binary-types) + - [Bytes (bytes)](#bytes-bytes) + - [Bytearray (bytearray)](#bytearray-bytearray) + - [Memoryview (memoryview)](#memoryview-memoryview) +- [None Type](#none-type) +- [Additional Topics](#additional-topics) + - [Integer Literals and Memory Sharing](#integer-literals-and-memory-sharing) + - [Type Casting](#type-casting) + - [Truthy and Falsy Values](#truthy-and-falsy-values) + - [isinstance() Function](#isinstance-function) + +## Numeric Types + +### Integer (int) + +Whole numbers without any decimal part, like `1`, `2`, `3`, `-1`, `-2`, etc. + +```python +num_int = 42 +print(type(num_int), "num_int =", num_int) # num_int = 42 +``` + +### Floating-Point (float) + +Numbers with decimal points, useful for measurements and precise values. + +```python +num_float = 3.14 +print(type(num_float), "num_float =", num_float) # num_float = 3.14 +``` + +### Complex (complex) + +Numbers with both real and imaginary components, used in advanced math and engineering. + +```python +num_complex = 2 + 3j +print(type(num_complex), "num_complex =", num_complex) # num_complex = (2+3j) + +# Accessing individual parts +z = 3 + 4j +print("Real Part:", z.real) # 3.0 +print("Imaginary Part:", z.imag) # 4.0 +``` + +## Boolean (bool) + +Simple True/False values, named after mathematician George Boole. + +```python +is_python_fun = True +print(type(is_python_fun), "is_python_fun =", is_python_fun) # is_python_fun = True + +# Useful for decision making +if is_python_fun: + print("Let's learn more Python!") +``` + +## Sequence Types + +### String (str) + +A sequence of characters (text), created using quotes. + +```python +text_double = "Hello, Python!" # Using double quotes +text_single = 'Hello, Python!' # Using single quotes +text_multi = '''This is a multi-line +string using triple quotes''' # Triple quotes for multi-line strings + +print(type(text_double), "text_double =", text_double) # text_double = Hello, Python! +``` + +### List (list) + +An ordered, mutable collection that can store different types of data. + +```python +my_list = [1, 2, 3, "Python", 3.14, 3+2j] +print(type(my_list), "my_list =", my_list) # my_list = [1, 2, 3, 'Python', 3.14, (3+2j)] + +# Lists can be modified +my_list[0] = 100 +print("Modified list:", my_list) # Modified list: [100, 2, 3, 'Python', 3.14, (3+2j)] +``` + +### Tuple (tuple) + +An ordered, immutable collection similar to lists but cannot be changed after creation. + +```python +my_tuple = (1, 2, 3, "AI", 2.71, False) +print(type(my_tuple), "my_tuple =", my_tuple) # my_tuple = (1, 2, 3, 'AI', 2.71, False) + +# Trying to modify a tuple will cause an error: +# my_tuple[0] = 100 # TypeError: 'tuple' object does not support item assignment +``` + +### Range (range) + +Represents a sequence of numbers, often used in loops. + +```python +num_range = range(1, 10, 2) # range(start, stop, step) +print(type(num_range), "num_range step =", num_range.step) # num_range step = 2 + +# To see all values in the range +print("Values in num_range:") +for i in num_range: + print(i) # Prints: 1, 3, 5, 7, 9 +``` + +## Set Types + +### Set (set) + +A mutable collection of unique items with no duplicates. + +```python +my_set = {1, 2, 33, 4, 4, 5} # Notice the duplicate 4 +print(type(my_set), "my_set =", my_set) # my_set = {1, 2, 33, 4, 5} + +# Adding to a set +my_set.add(100) +print("Set after adding 100:", my_set) # Set after adding 100: {1, 2, 33, 4, 5, 100} +``` + +### Frozen Set (frozenset) + +An immutable version of a set that cannot be changed after creation. + +```python +frozen_set = frozenset([11, 2, 3, 4, 4, 5]) +print(type(frozen_set), "frozen_set =", frozen_set) # frozen_set = frozenset({11, 2, 3, 4, 5}) + +# Trying to modify a frozen set will cause an error: +# frozen_set.add(100) # AttributeError: 'frozenset' object has no attribute 'add' +``` + +## Mapping Type + +### Dictionary (dict) + +Stores key-value pairs, similar to a real dictionary with words and definitions. + +```python +my_dict = {"name": "Alice", "age": 25, "language": "Python"} +print(type(my_dict), "my_dict =", my_dict) # my_dict = {'name': 'Alice', 'age': 25, 'language': 'Python'} + +# Access values using their keys +print("Name:", my_dict["name"]) # Name: Alice +print("Age:", my_dict["age"]) # Age: 25 + +# Dictionaries are mutable +my_dict["age"] = 26 +print("Updated dictionary:", my_dict) # Updated dictionary: {'name': 'Alice', 'age': 26, 'language': 'Python'} + +# Adding new key-value pairs +my_dict["hobby"] = "Coding" +print("Dictionary with new key:", my_dict) # Dictionary with new key: {'name': 'Alice', 'age': 26, 'language': 'Python', 'hobby': 'Coding'} +``` + +## Binary Types + +### Bytes (bytes) + +Immutable sequence of bytes, useful for handling binary data. + +```python +byte_data = b"Hello" # The 'b' prefix indicates bytes data +print(type(byte_data), "byte_data =", byte_data) # byte_data = b'Hello' + +# Each character in bytes corresponds to its ASCII value +print("First byte:", byte_data[0]) # First byte: 72 (ASCII value for 'H') + +# Example for reading/writing binary data: +# with open("image.jpg", "rb") as image_file: +# image_data = image_file.read() +# +# with open("copy.jpg", "wb") as target_file: +# target_file.write(image_data) +``` + +### Bytearray (bytearray) + +Mutable sequence of bytes that can be modified after creation. + +```python +byte_array = bytearray([65, 66, 67, 69]) # ASCII values: A=65, B=66, C=67, E=69 +print(type(byte_array), "byte_array =", byte_array) # byte_array = bytearray(b'ABCE') + +# Inspecting bytes +print("First byte value:", byte_array[0]) # First byte value: 65 +print("First byte as character:", chr(byte_array[0])) # First byte as character: A + +# Converting to a string +print("Decoded string:", byte_array.decode('utf-8')) # Decoded string: ABCE + +# Modifying bytearrays +ba = bytearray(b"hello") +print("Before change:", ba) # Before change: bytearray(b'hello') +ba[0] = 72 # Change 'h' (ASCII 104) to 'H' (ASCII 72) +print("After change:", ba) # After change: bytearray(b'Hello') +``` + +### Memoryview (memoryview) + +An efficient way to work with binary data without making copies. + +```python +mem_view = memoryview(b"Operation Badar") +print(type(mem_view), "mem_view =", mem_view) # mem_view = + +# Extracting parts of the data +print("First 5 bytes as bytes:", bytes(mem_view[0:5])) # First 5 bytes as bytes: b'Opera' +``` + +## None Type + +Represents the absence of a value or a null value. + +```python +x = None +y = None +z = x + +print("Type of None:", type(x)) # Type of None: +print("x == y:", x == y) # x == y: True (same value) +print("x is y:", x is y) # x is y: True (same object - None is a singleton) + +# Functions with no return statement return None by default +def function_that_returns_nothing(): + print("This function did something but doesn't return a value") + +result = function_that_returns_nothing() +print("Result:", result) # Result: None + +# None is treated as False in conditions +if None: + print("This won't print") +else: + print("None is treated as False in conditions") # This will print +``` + +## Additional Topics + +### Integer Literals and Memory Sharing + +Python optimizes memory by reusing objects for small integers. + +```python +# Integers between -5 and 256 share the same object +small_num1 = 42 +small_num2 = 42 +print("small_num1 is small_num2:", small_num1 is small_num2) # True - same object + +# Larger integers are separate objects +large_num1 = 1000 +large_num2 = 1000 +print("large_num1 is large_num2:", large_num1 is large_num2) # False - different objects +print("large_num1 == large_num2:", large_num1 == large_num2) # True - same value +``` + +### Type Casting + +Converting data from one type to another. + +```python +# Implicit type casting (automatic) +i = 10 # Integer +j = 20.6 # Float +f = i + j # i is automatically converted to float +print("i + j =", f, "Type:", type(f)) # i + j = 30.6 Type: + +# Explicit type casting (manual) +f1 = 66.89 +i1 = int(f1) # Converts float to int (truncates decimal part) +print(f"{f1} as an integer:", i1) # 66.89 as an integer: 66 + +# String to float +s = "25.8" +f2 = float(s) +print(f"The string '{s}' as a float:", f2) # The string '25.8' as a float: 25.8 + +# String with decimal to integer (two-step process) +i2 = int(float("25.8")) +print(f"The string '25.8' as an integer:", i2) # The string '25.8' as an integer: 25 + +# Converting to boolean +print("42 as a boolean:", bool(42)) # True (non-zero is True) +print("0 as a boolean:", bool(0)) # False (zero is False) +print("'Hello' as a boolean:", bool("Hello")) # True (non-empty string is True) +print("'' as a boolean:", bool("")) # False (empty string is False) +``` + +### Truthy and Falsy Values + +Some values are treated as True or False in conditions. + +```python +# Truthy values (treated as True): +truthy_examples = [42, -1, "hello", [1, 2], {"a": 1}] + +print("Truthy values (these are treated as True):") +for value in truthy_examples: + print(f" {value} is {bool(value)}") + +# Falsy values (treated as False): +falsy_examples = [0, None, "", [], {}, set()] + +print("\nFalsy values (these are treated as False):") +for value in falsy_examples: + print(f" {repr(value)} is {bool(value)}") + +# Example in a condition: +name = "" # Empty string - falsy +if name: + print(f"Hello, {name}!") +else: + print("Hello, anonymous user!") # This will print +``` + +### isinstance() Function + +Used to check if a value is of a certain type. + +```python +age = 20 +weight = 66.89 + +# Checking specific types +print("Is age an integer?", isinstance(age, int)) # True +print("Is weight an integer?", isinstance(weight, int)) # False +print("Is weight a float?", isinstance(weight, float)) # True + +# Checking multiple types at once +print("Is age either an int or float?", isinstance(age, (int, float))) # True +print("Is weight either an int or float?", isinstance(weight, (int, float))) # True + +# Practical application +def greet_person(name): + # Validate input type + if not isinstance(name, str): + print("Error: name must be a string") + return + + print(f"Hello, {name.title()}!") + +greet_person("alice") # Works fine: Hello, Alice! +greet_person(123) # Shows error message +``` + diff --git a/00_python_colab/03_operators_keywords_variables/readme.md b/00_python_colab/03_operators_keywords_variables/readme.md index 4bece4b..6a08c09 100644 --- a/00_python_colab/03_operators_keywords_variables/readme.md +++ b/00_python_colab/03_operators_keywords_variables/readme.md @@ -1 +1,297 @@ -# [Lesson 03: Operators, Keywords & Variables](https://colab.research.google.com/drive/1ct5Efj7xRRpu155NOx38dNgnpQgC25yv?usp=sharing) +# Python Operators and Variables + +A comprehensive guide to understanding Python operators and variables with clear definitions and well-commented code examples. + +## Table of Contents + +- [Overview](#overview) +- [Operators and Operands](#operators-and-operands) + - [Unary Operators](#unary-operators-work-with-just-one-value) + - [Binary Operators](#binary-operators-work-with-two-values) +- [Types of Operators in Python](#types-of-operators-in-python) + - [1. Arithmetic Operators](#1-arithmetic-operators-for-math-calculations) + - [2. Comparison Operators](#2-comparison-operators-for-comparing-values) + - [3. Logical Operators](#3-logical-operators-for-combining-conditions) + - [4. Assignment Operators](#4-assignment-operators-for-storing-values-in-variables) + - [5. Identity Operators](#5-identity-operators-for-checking-if-objects-are-the-same-in-memory) + - [6. Membership Operators](#6-membership-operators-for-checking-if-a-value-is-in-a-collection) +- [Python Keywords](#python-keywords) +- [Python Variables](#python-variables) + - [Rules for Variable Names](#rules-for-variable-names) + - [Naming Conventions](#naming-conventions) + - [Multiple Variable Assignment](#multiple-variable-assignment) + - [Deleting Variables](#deleting-variables) +- [License](#license) +- [Contributing](#contributing) + +## Overview + +This repository provides a beginner-friendly guide to Python operators and variables. Each concept is explained in simple terms with practical code examples to help solidify your understanding. + +## Operators and Operands + +**Operator**: A symbol that tells Python to perform a specific action or calculation (like `+`, `-`, `*`). +**Operand**: The values or variables that the operator works on. + +```python +# Example: In the expression 3 + 4 +# + is the operator (it tells Python to add) +# 3 and 4 are the operands (the values being added) + +result = 3 + 4 # The operator (+) works on the operands (3 and 4) +``` + +### Unary Operators (work with just one value) + +Unary operators need only one value to work with. + +```python +# Negative operator: Changes a positive number to negative or vice versa +x = 5 +y = -x # The - operator flips the sign of x, so y becomes -5 +print(y) # Output: -5 + +# Logical NOT: Flips True to False or False to True +a = True +b = not a # The 'not' operator reverses the boolean value +print(b) # Output: False + +# Bitwise NOT: Flips each binary digit (0β†’1, 1β†’0) +x = 5 # In binary: 0101 +y = ~x # ~ flips all bits, resulting in -6 in decimal +print(y) # Output: -6 +``` + +### Binary Operators (work with two values) + +Binary operators need two values to work with. These are covered in detail in the following sections. + +## Types of Operators in Python + +### 1. Arithmetic Operators (for math calculations) + +```python +a = 10 +b = 3 + +# Addition: Adds two numbers +print(a + b) # Output: 13 + +# Subtraction: Subtracts second number from first +print(a - b) # Output: 7 + +# Multiplication: Multiplies two numbers +print(a * b) # Output: 30 + +# Division: Divides first number by second (always gives a float) +print(a / b) # Output: 3.3333... + +# Floor Division: Divides and rounds down to nearest whole number +print(a // b) # Output: 3 + +# Modulus: Returns the remainder after division +print(a % b) # Output: 1 + +# Exponentiation: Raises first number to power of second +print(a ** b) # Output: 1000 (10Β³ = 10Γ—10Γ—10) +``` + +### 2. Comparison Operators (for comparing values) + +```python +x = 10 +y = 5 + +# Equal to: Checks if two values are the same +print(x == y) # Output: False + +# Not equal to: Checks if two values are different +print(x != y) # Output: True + +# Greater than: Checks if first value is larger than second +print(x > y) # Output: True + +# Less than: Checks if first value is smaller than second +print(x < y) # Output: False + +# Greater than or equal to: Checks if first value is at least as large as second +print(x >= y) # Output: True + +# Less than or equal to: Checks if first value is at most as large as second +print(x <= y) # Output: False +``` + +### 3. Logical Operators (for combining conditions) + +```python +x = True +y = False + +# AND: Returns True only if both conditions are True +print(x and y) # Output: False (since y is False) + +# OR: Returns True if at least one condition is True +print(x or y) # Output: True (since x is True) + +# NOT: Reverses the result, True becomes False and vice versa +print(not x) # Output: False (opposite of True) +``` + +### 4. Assignment Operators (for storing values in variables) + +```python +# Simple assignment: Stores a value in a variable +x = 5 +print(x) # Output: 5 + +# Add and assign: Adds right value to the variable, then updates variable +x += 3 # Same as writing x = x + 3 +print(x) # Output: 8 + +# Subtract and assign: Subtracts right value from variable, then updates variable +x -= 3 # Same as writing x = x - 3 +print(x) # Output: 5 + +# Multiply and assign: Multiplies variable by right value, then updates variable +x *= 3 # Same as writing x = x * 3 +print(x) # Output: 15 + +# Divide and assign: Divides variable by right value, then updates variable +x /= 3 # Same as writing x = x / 3 +print(x) # Output: 5.0 (notice it's now a float) + +# Floor divide and assign: Divides and rounds down, then updates variable +x //= 3 # Same as writing x = x // 3 +print(x) # Output: 1.0 +``` + +### 5. Identity Operators (for checking if objects are the same in memory) + +```python +# Create two lists with the same values +a = [1, 2, 3] +b = [1, 2, 3] +# Make c point to the same list as a +c = a + +# 'is' checks if two variables point to exactly the same object in memory +print(a is c) # Output: True (they point to the same list) +print(a is b) # Output: False (different lists with same values) + +# '==' checks if two variables have the same values +print(a == b) # Output: True (the lists contain the same values) + +# 'is not' checks if two variables point to different objects +print(a is not b) # Output: True (they are different objects) + +# We can see the memory locations using id() +print(id(a)) # Prints memory address, e.g., 134193929171776 +print(id(b)) # Different address, e.g., 134193940649408 +print(id(c)) # Same as a's address, confirming they are the same object +``` + +### 6. Membership Operators (for checking if a value is in a collection) + +```python +# Create a list of numbers +my_list = [1, 2, 3, 4, 5] + +# 'in' checks if a value exists in a collection +print(3 in my_list) # Output: True (3 is in the list) + +# 'not in' checks if a value doesn't exist in a collection +print(10 not in my_list) # Output: True (10 is not in the list) + +# These operators also work with strings +my_string = "Operation Badar" +print('O' in my_string) # Output: True (the letter O is in the string) +print('Hello' not in my_string) # Output: True (the word Hello is not in the string) +``` + +## Python Keywords + +**Keywords**: Special reserved words in Python that have predefined meanings. You cannot use them as variable names. + +```python +import keyword +print(keyword.kwlist) # Prints all Python keywords +# Example keywords: 'if', 'else', 'for', 'while', 'def', 'class', 'True', 'False', etc. +``` + +## Python Variables + +**Variables**: Names that store data values. Think of them as labeled boxes where you can put information. + +### Rules for Variable Names + +1. Can contain letters, digits, and underscores +2. Cannot start with a digit +3. Are case-sensitive (`name` and `Name` are different variables) +4. Cannot be Python keywords + +```python +# Good variable names +name = "Alice" # Stores a string +_age = 25 # Starts with underscore (valid) +salary2024 = 50000 # Contains numbers (but doesn't start with one) +my_variable = "Python" # Uses underscores for readability + +# Bad variable names (these would cause errors) +# 2name = "Bob" # Cannot start with a number +# my-variable = "Error" # Cannot use hyphens +# class = "CS101" # Cannot use Python keywords as variable names +``` + +### Naming Conventions + +```python +# snake_case for variables and functions +total_cost = 100 +def calculate_tax(): + pass + +# CamelCase or PascalCase for classes +class BankAccount: + pass + +# UPPER_CASE for constants (values that don't change) +MAX_SPEED = 120 +PI = 3.14159 + +# _single_underscore for "private" variables (hint to other programmers) +_password = "secret123" + +# __double_underscore for special Python name mangling +__secret_key = "very_secret" + +# __dunder__ for special Python methods +def __init__(self): + pass +``` + +### Multiple Variable Assignment + +```python +# You can assign multiple values at once (very handy!) +x, y, z = 1, 2.5, "Python" +# This creates three variables: +# x gets 1 (an integer) +# y gets 2.5 (a float) +# z gets "Python" (a string) +print(x, y, z) # Output: 1 2.5 Python +``` + +### Deleting Variables + +```python +# Create a variable +x = 10 +print(x) # Output: 10 + +# Delete the variable from memory +del x # The variable x no longer exists + +# If we try to use x now, we'll get an error +# print(x) # Would raise: NameError: name 'x' is not defined +``` + diff --git a/00_python_colab/04_strings_casting/readme.md b/00_python_colab/04_strings_casting/readme.md index 21d59f7..437cc25 100644 --- a/00_python_colab/04_strings_casting/readme.md +++ b/00_python_colab/04_strings_casting/readme.md @@ -1 +1,307 @@ -# [Lesson 04: Strings & Type Casting](https://colab.research.google.com/drive/1Ho_ZEbgOB_Y3YjtPWqoJwjVXgpmM5fQS?usp=sharing) +# πŸ“š Python Strings + +Welcome! +This document covers everything you need to know about **Python Strings**, explained in **easy language** with **simple examples and comments**. + +--- + +## πŸ”Ή What is a String? + +- A **string** is a sequence of characters like letters, numbers, or symbols. +- In Python, strings are **immutable** (you can't change them after creation). + +--- + +## πŸ”Ή Creating Strings + +You can create strings using **single**, **double**, or **triple quotes**: + +```python +# Using single quotes +single_quote = 'Hello, World!' + +# Using double quotes +double_quote = "Hello, World!" + +# Using triple quotes for multi-line strings +multi_line = '''Hello, +World!''' + +# Using raw strings (special characters are treated as normal text) +raw_string = r'Hello\nWorld!' +``` + +--- + +## πŸ”Ή Escape Sequences + +**Escape sequences** are special codes inside strings starting with a backslash (`\`): + +```python +print("Hello,\tWorld!") # \t adds a tab space +print("Hello,\nWorld!") # \n moves to a new line +print("Hello, \"World!\"") # \" prints double quotes inside the string +print("Hello,\\World!") # \\ prints a single backslash +``` + +--- + +## πŸ”Ή Unicode Characters + +Python supports **Unicode**, meaning it can handle characters from many languages: + +```python +print("\u0041") # Prints 'A' +print("\u0042") # Prints 'B' +``` + +--- + +## πŸ”Ή String Operations + +You can **join**, **slice**, **find length**, and **change case** of strings: + +```python +# String Concatenation (joining strings) +greeting = "Hello" + ", " + "World!" # Result: "Hello, World!" + +# Indexing (getting one character) +first_char = "Python"[0] # 'P' +second_char = "Python"[1] # 'y' + +# Slicing (getting part of string) +text = "Python Programming" +first_word = text[0:6] # 'Python' +last_word = text[7:] # 'Programming' + +# Length of string +length = len("Hello World") # 11 + +# Changing case +upper_case = "hello".upper() # 'HELLO' +lower_case = "HELLO".lower() # 'hello' +``` + +--- + +## πŸ”Ή String Methods + +### ➑️ split() + +Breaks a string into parts: + +```python +# Split by comma +text = "apple,banana,orange" +fruits = text.split(",") # ['apple', 'banana', 'orange'] + +# Split by spaces +sentence = "Hello World Python" +words = sentence.split() # ['Hello', 'World', 'Python'] +``` + +--- + +### ➑️ join() + +Joins a list of strings into one string: + +```python +fruits = ['apple', 'banana', 'orange'] +text = ", ".join(fruits) # "apple, banana, orange" +``` + +--- + +### ➑️ replace() + +Replaces part of a string with something else: + +```python +text = "Hello, World!" +new_text = text.replace("Hello", "Hi") # "Hi, World!" +``` + +--- + +### ➑️ find() and index() + +Finds the **position** of a substring: + +```python +text = "Hello, World!" + +# find() returns the index or -1 if not found +position = text.find("World") # 7 +not_found = text.find("Python") # -1 + +# index() returns the index but gives an error if not found +position = text.index("World") # 7 +# text.index("Python") β†’ Raises ValueError +``` + +--- + +### ➑️ count() + +Counts how many times something appears: + +```python +text = "hello hello world" +count = text.count("hello") # 2 +``` + +--- + +## πŸ”Ή String Formatting (Inserting values into strings) + +### ➑️ Using % Operator + +```python +name = "John" +age = 30 +message = "My name is %s and I am %d years old." % (name, age) +# "My name is John and I am 30 years old." +``` + +--- + +### ➑️ Using str.format() Method + +```python +name = "John" +age = 30 +message = "My name is {} and I am {} years old.".format(name, age) +# "My name is John and I am 30 years old." + +# Using indexes +message = "I am {1} years old and my name is {0}.".format(name, age) +# "I am 30 years old and my name is John." +``` + +--- + +### ➑️ Using f-Strings (Best Way) + +```python +name = "John" +age = 30 +message = f"My name is {name} and I am {age} years old." +# "My name is John and I am 30 years old." +``` + +--- + +## πŸ”Ή String Memory Management + +Python tries to **save memory** by reusing strings. + +### ➑️ String Literal Pool + +```python +# Same small strings are stored only once +a = "hello" +b = "hello" +print(a is b) # True +``` + +--- + +### ➑️ String Interning + +```python +import sys + +# Interning manually +a = sys.intern("hello world!") +b = sys.intern("hello world!") +print(a is b) # True +``` + +--- + +### ➑️ Strings Not Always Interned + +```python +# Long strings may not be interned automatically +a = "this is a very long string" +b = "this is a very long string" +print(a is b) # Might be False + +# Dynamically created strings +a = "hello" +b = "world" +c = a + b +d = "helloworld" +print(c is d) # False +``` + +--- + +## πŸ”Ή String Repetition + +You can **repeat** strings using `*`: + +```python +# Repeat a character 20 times +separator = "-" * 20 # "--------------------" + +# Repeat patterns +pattern = "*" * 5 # "*****" + +# Example: Create a simple triangle +for i in range(1, 6): + print("*" * i) +# Output: +# * +# ** +# *** +# **** +# ***** +``` + +--- + +## πŸ”Ή String Comparisons + +Python compares strings by the **dictionary order** (alphabetical): + +```python +print("apple" < "banana") # True +print("apple" == "Apple") # False (case matters) +print("abc" < "abd") # True +``` + +--- + +## πŸ”Ή Type Casting with Strings + +Convert between **strings**, **integers**, **floats**, and **lists**: + +```python +# String to Integer +num_str = "123" +num_int = int(num_str) # 123 + +# Integer to String +num = 456 +num_str = str(num) # "456" + +# String to Float +pi_str = "3.14" +pi_float = float(pi_str) # 3.14 + +# String to List +list_of_chars = list("Python") # ['P', 'y', 't', 'h', 'o', 'n'] + +# List to String +joined_string = ''.join(['P', 'y', 't', 'h', 'o', 'n']) # "Python" +``` + +--- + +# βœ… Conclusion + +- **Strings** are a very important data type in Python. +- You can **create**, **modify**, **analyze**, and **format** strings easily. +- **Understanding string memory** and **optimization** can help you write better Python programs. diff --git a/00_python_colab/05_control_flow/readme.md b/00_python_colab/05_control_flow/readme.md index a3b4f80..9cfc358 100644 --- a/00_python_colab/05_control_flow/readme.md +++ b/00_python_colab/05_control_flow/readme.md @@ -1 +1,362 @@ -# [Lesson 05: Control Flow & Loops](https://colab.research.google.com/drive/19CfIJYDVeQJAeGw-L2MuPuxAhMJGA8Cm?usp=sharing) +# 🌟 Control Flow, Decision Making, and Loops in Python + +## 1. What is Control Flow? + +βž” **Control flow** means how your program decides **which code to run first, next, or skip** based on some conditions. + +Python uses: +- `if` +- `elif` +- `else` +- **Comparison operators** (`>`, `<`, `==`, etc.) +- **Logical operators** (`and`, `or`, `not`) + +--- + +## 2. Comparison Operators + +βž” Used to **compare** two values. +They **return** `True` or `False`. + +| Operator | Meaning | Example | +|:--------:|:-------------------------:|:-------------------:| +| == | Equal to | `5 == 5 β†’ True` | +| != | Not equal to | `5 != 3 β†’ True` | +| > | Greater than | `7 > 3 β†’ True` | +| < | Less than | `2 < 8 β†’ True` | +| >= | Greater than or equal to | `5 >= 5 β†’ True` | +| <= | Less than or equal to | `3 <= 4 β†’ True` | + +### Example: +```python +x: int = 10 +y: int = 20 + +print("x == y =", x == y) # False +print("x != y =", x != y) # True +print("x > y =", x > y) # False +print("x < y =", x < y) # True +print("x >= y =", x >= y) # False +print("x <= y =", x <= y) # True +``` + +--- + +## 3. Logical Operators + +βž” Combine multiple conditions. + +| Operator | Meaning | Example | +|:--------:|:---------------------------------:|:-------------------------:| +| and | Both conditions must be `True` | `5 > 2 and 6 > 3 β†’ True` | +| or | At least one must be `True` | `5 < 2 or 6 > 3 β†’ True` | +| not | Reverses the condition | `not (5 > 2) β†’ False` | + +### Example: +```python +age: int = 25 +is_student: bool = True + +if age > 18 and is_student: + print("You are eligible for a student discount.") + +if age < 12 or age > 60: + print("You qualify for a special discount.") + +if not is_student: + print("You are not a student.") +``` + +--- + +## 4. if Statement + +βž” **Check a condition**, and if it's `True`, run the code inside. + +### Example: +```python +num: int = 10 + +if num > 0: + print("The number is positive.") +``` + +--- + +## 5. else Statement + +βž” **Run when the if condition is False**. + +### Example: +```python +num: int = -5 + +if num > 0: + print("The number is positive.") +else: + print("The number is not positive.") +``` + +--- + +## 6. elif Statement + +βž” **Check another condition** if the previous ones were False. + +### Example: +```python +num: int = 0 + +if num > 0: + print("The number is positive.") +elif num < 0: + print("The number is negative.") +else: + print("The number is zero.") +``` + +--- + +## 7. Nested if Statements + +βž” **if inside another if**. + +### Example: +```python +num: int = 10 + +if num > 0: + if num % 2 == 0: + print("The number is positive and even.") + else: + print("The number is positive and odd.") +else: + print("The number is negative.") +``` + +--- + +## 8. Practical Examples + +### Example 1: Simple Calculator +```python +operation: str = input("Enter the operation (+, -, *, /): ") +num1: float = float(input("Enter the first number: ")) +num2: float = float(input("Enter the second number: ")) + +if operation == '+': + result = num1 + num2 +elif operation == '-': + result = num1 - num2 +elif operation == '*': + result = num1 * num2 +elif operation == '/': + if num2 != 0: + result = num1 / num2 + else: + result = "Error: Division by zero." +else: + result = "Invalid operation." + +print("Result:", result) +``` + +--- + +### Example 2: Advanced Calculator +```python +def calculator(): + """ + A calculator that can do +, -, *, /, %, //, and ** operations. + """ + while True: + operation = input("Enter the operation (+, -, *, /, %, //, ** or 'q' to quit): ") + + if operation.lower() == 'q': + break + + if operation not in ('+', '-', '*', '/', '%', '//', '**'): + print("Invalid operation.") + continue + + try: + num1 = float(input("Enter the first number: ")) + num2 = float(input("Enter the second number: ")) + except ValueError: + print("Invalid input. Please enter numbers only.") + continue + + if operation == '+': + result = num1 + num2 + elif operation == '-': + result = num1 - num2 + elif operation == '*': + result = num1 * num2 + elif operation == '/': + if num2 != 0: + result = num1 / num2 + else: + print("Error: Division by zero.") + continue + elif operation == '%': + result = num1 % num2 + elif operation == '//': + if num2 != 0: + result = num1 // num2 + else: + print("Error: Division by zero.") + continue + elif operation == '**': + result = num1 ** num2 + + print("Result:", result) + +calculator() +``` + +--- + +### Example 3: Grading System +```python +def grading_system(marks): + """ + Returns grade based on marks. + """ + if marks >= 90: + grade = "A+" + elif marks >= 80: + grade = "A" + elif marks >= 70: + grade = "B" + elif marks >= 60: + grade = "C" + elif marks >= 50: + grade = "D" + else: + grade = "F" + return grade + +while True: + try: + marks = float(input("Enter the marks: ")) + if 0 <= marks <= 100: + break + else: + print("Marks must be between 0 and 100.") + except ValueError: + print("Invalid input. Please enter a number.") + +grade = grading_system(marks) + +print(f"The grade for {marks} marks is: {grade}") +``` + +--- + +# ✨ match-case Statement (Python 3.10+) + +βž” **A better way to replace multiple if-elif-else**. + +### Example: +```python +def check_status(code): + """ + Check HTTP status codes. + """ + match code: + case 200: + print("OK") + case 400: + print("Bad Request") + case 404: + print("Not Found") + case _: + print("Unknown Status") + +check_status(200) # Output: OK +check_status(404) # Output: Not Found +check_status(500) # Output: Unknown Status +``` + +--- + +# πŸ”„ Loops and Iterations in Python + +## 1. What are Loops? + +βž” **Loops** repeat code multiple times. + +Python has two main types: +- `for` loop β€” known number of times +- `while` loop β€” unknown number, repeat until condition becomes False + +--- + +## 2. for Loop (Fixed repetitions) + +### Example: List +```python +fruits: list = ["apple", "banana", "cherry"] + +for fruit in fruits: + print(fruit) +``` +**Output:** +``` +apple +banana +cherry +``` + +--- + +### Example: String +```python +word: str = "Python" + +for letter in word: + print(letter) +``` +**Output:** +``` +P +y +t +h +o +n +``` + +--- + +## 3. for Loop with else + +βž” **`else` runs if the loop didn't break early.** + +### Example: +```python +numbers = [1, 2, 3] + +for num in numbers: + print(num) +else: + print("All numbers printed without break.") +``` +**Output:** +``` +1 +2 +3 +All numbers printed without break. +``` + +--- + +# βœ… Summary + +- **if-elif-else** is used for decision making. +- **Logical operators** combine multiple conditions. +- **match-case** is cleaner (Python 3.10+). +- **Loops** help repeat actions. +- **for-else** structure is useful for some special cases. + diff --git a/00_python_colab/06_lists_tuples_dict/readme.md b/00_python_colab/06_lists_tuples_dict/readme.md index f4bc514..27e5a0b 100644 --- a/00_python_colab/06_lists_tuples_dict/readme.md +++ b/00_python_colab/06_lists_tuples_dict/readme.md @@ -1 +1,247 @@ -# [Lesson 06: Lists, Tuples & Dictionary](https://colab.research.google.com/drive/1yPH2ErmQWlOli9HZR1l2EBUB5FIGY-tZ?usp=sharing) +# Python Collections: Lists, Tuples, and Dictionaries πŸ“š + +Welcome! This guide provides a simple, clear explanation of three important Python collections: **Lists**, **Tuples**, and **Dictionaries**. +Perfect for beginners who want easy definitions, examples, and real-life comparisons! + +--- + +## πŸ“œ 1. Lists in Python + +**Easy Definition:** +A **list** is like a **shopping bag** β€” you can put things in, remove them, change them, and they stay in the order you added them. + +### Characteristics: +- **Ordered:** Items stay in the order you add them. +- **Mutable:** You can change, add, or remove items. +- **Indexed:** Each item has a position (starting at 0). +- **Dynamic Size:** Lists can grow or shrink. +- **Heterogeneous:** Can contain different data types. +- **Supports Duplicates:** Same item can appear multiple times. + +### 🌟 Creating a List: +```python +# Example: A shopping list +fruits: list = ["apple", "banana", "cherry"] + +# Example: A list of lucky numbers +numbers: list = [10, 20, 30, 40] +``` + +### 🌟 Accessing List Elements: +```python +print(fruits[0]) # Output: apple +print(fruits[-1]) # Output: cherry +``` + +### 🌟 Modifying Lists: +```python +fruits[0] = "watermelon" +print(fruits) # ['watermelon', 'banana', 'cherry'] +``` + +### 🌟 List Slicing: +```python +print(fruits[0:2]) # ['watermelon', 'banana'] +``` + +--- + +## πŸ“œ 2. Common List Methods + +### 🌟 Appending and Extending: +```python +fruits.append("orange") +fruits.extend(["grapes", "pineapple"]) +``` + +### 🌟 Removing Elements: +```python +fruits.remove("banana") +fruits.pop() +fruits.pop(0) +``` + +### 🌟 Sorting a List: +```python +numbers.sort() +numbers.sort(reverse=True) +fruits.sort(key=len) # By length +fruits.sort(key=lambda x: x[-1]) # By last character +``` + +--- + +## πŸ“œ 3. Iterating Over Lists +```python +for fruit in fruits: + print(fruit) +``` + +### 🌟 List Comprehension: +```python +squares = [x**2 for x in [1, 2, 3, 4, 5]] +print(squares) # [1, 4, 9, 16, 25] +``` + +--- + +## πŸ“œ 4. Tuples in Python + +**Easy Definition:** +A **tuple** is like a **sealed box** β€” you can look inside, but you can’t change anything. + +### Characteristics: +- **Ordered** +- **Immutable** +- **Hashable** (usable as dictionary keys) + +### 🌟 Creating a Tuple: +```python +tuple1: tuple = ("apple", "banana", "cherry") +tuple2: tuple = (10, 20, 30) +``` + +### 🌟 Accessing Tuples: +```python +print(tuple1[0]) # apple +``` + +### 🌟 Attempting to Modify Tuple (Not Allowed): +```python +# tuple1[0] = "watermelon" +# ❌ Error: 'tuple' object does not support item assignment +``` + +--- + +## πŸ“œ 5. Dictionaries in Python + +**Easy Definition:** +A **dictionary** is like a **real dictionary** β€” you search using a word (key) and get its meaning (value). + +### Characteristics: +- **Ordered** +- **Mutable** +- **Unindexed** (access with keys, not numbers) +- **No Duplicate Keys** + +### 🌟 Creating a Dictionary: +```python +person: dict = { + "name": "Alice", + "age": 25, + "city": "New York" +} +``` + +### 🌟 Accessing Values: +```python +print(person["name"]) # Alice +print(person.get("city")) # New York +``` + +### 🌟 Modifying a Dictionary: +```python +person["age"] = 26 +person["email"] = "alice@example.com" +``` + +### 🌟 Deleting Items: +```python +del person["city"] +email = person.pop("email") +``` + +--- + +## πŸ“œ 6. Dictionary Methods + +```python +print(person.keys()) +print(person.values()) +print(person.items()) + +person.clear() + +person.update({"name": "Bob", "age": 30}) +``` + +--- + +## πŸ“œ 7. Iterating Over a Dictionary + +```python +# Loop through keys +for key in person: + print(key) + +# Loop through values +for value in person.values(): + print(value) + +# Loop through key-value pairs +for key, value in person.items(): + print(f"{key}: {value}") +``` + +--- + +## πŸ“œ 8. Practical Examples + +### 🌟 Phonebook Example: +```python +phonebook = { + "Alice": "1234", + "Bob": "5678", + "Charlie": "91011" +} +print(phonebook["Bob"]) +``` + +### 🌟 Counting Word Frequencies: +```python +text = "apple banana apple orange banana apple" +words = text.split() +word_count = {} + +for word in words: + if word in word_count: + word_count[word] += 1 + else: + word_count[word] = 1 + +print(word_count) +``` + +--- + +## πŸ“œ 9. Common Pitfalls + +- ❌ **Accessing a non-existing key** + β†’ Raises KeyError. + ➑ **Use `.get()`** instead if unsure. + +- ❌ **Keys must be immutable** + β†’ Only strings, numbers, and tuples can be dictionary keys. + +--- + +## πŸ“œ 10. Dictionary Comprehensions + +### 🌟 Easy Way to Create a Dictionary: +```python +numbers = [1, 2, 3, 4, 5] +doubled = {num: num*2 for num in numbers} +print(doubled) # {1: 2, 2: 4, 3: 6, 4: 8, 5: 10} +``` + +--- + +# 🎯 Quick Summary with Real-Life Examples: + +| Python Collection | Real-Life Example | +|-------------------|-------------------| +| List πŸ›’ | Shopping List | +| Tuple πŸ“¦ | Sealed Box | +| Dictionary πŸ“– | Real Dictionary | + diff --git a/00_python_colab/07_sets/readme.md b/00_python_colab/07_sets/readme.md index cad15f4..44573b8 100644 --- a/00_python_colab/07_sets/readme.md +++ b/00_python_colab/07_sets/readme.md @@ -1 +1,219 @@ -# [Lesson 07: The Set & Frozenset](https://colab.research.google.com/drive/1qsMQMYeeu-XpOEDW2s4JgQ24AwqVcuoW?usp=sharing) +# Python Sets + +## 1. What is a Set? + +A **Set** is a built-in Python data type that: +- βœ… Stores **unique elements** (no duplicates) +- βœ… Is **unordered** (no fixed position for items) +- βœ… Is **mutable** (can add/remove items) +- βœ… Only allows **immutable items** (numbers, strings, tuples) + +**Example:** + +```python +my_set = {1, 2, 3, "hello", (4, 5)} +# my_set = {[1, 2]} ❌ Error! Lists are mutable. +``` + +--- + +## 2. How to Create a Set + +- Use `{}` for non-empty sets. +- Use `set()` for empty sets (because `{}` creates a dictionary). + +**Example:** + +```python +set1 = {1, 2, 3} +set2 = set([4, 5, 6]) # Converts list to set +empty_set = set() # βœ… Correct way +# wrong_empty = {} ❌ Creates a dictionary! +``` + +--- + +## 3. Key Properties of Sets + +### βœ” Unordered (No Indexing) + +Items do not have a fixed position. +Cannot access items using an index like `my_set[0]`. + +```python +my_set = {10, 20, 30} +# print(my_set[0]) ❌ Error! No indexing. +``` + +--- + +### βœ” Unchangeable Items (But Set is Mutable) + +You cannot modify an existing item directly, +but you can **add** or **remove** items. + +```python +my_set = {1, 2, 3} +my_set.add(4) # βœ… Adds 4 +my_set.remove(2) # βœ… Removes 2 +# my_set[0] = 99 ❌ Error! Cannot modify items directly. +``` + +--- + +### βœ” Only Unique Elements (No Duplicates) + +```python +numbers = {1, 2, 2, 3} +print(numbers) # Output: {1, 2, 3} (duplicates removed) +``` + +--- + +### βœ” Only Immutable Items Allowed + +Allowed: `int`, `float`, `str`, `tuple` +Not Allowed: `list`, `dict`, `set` + +```python +valid_set = {1, "hello", (4, 5)} +# invalid_set = {[1, 2]} ❌ Error! Lists are mutable. +``` + +--- + +## 4. Set Methods + +### πŸ”Ή Adding & Removing Items + +| Method | Description | Example | +|-------------|-------------------------------------|-----------------------| +| `add(x)` | Adds one item | `my_set.add(5)` | +| `remove(x)` | Removes item (error if missing) | `my_set.remove(5)` | +| `discard(x)`| Removes item (no error if missing) | `my_set.discard(5)` | +| `pop()` | Removes a random item | `my_set.pop()` | +| `clear()` | Removes all items | `my_set.clear()` | + +**Example:** + +```python +nums = {1, 2, 3} +nums.add(4) # {1, 2, 3, 4} +nums.discard(2) # {1, 3, 4} +nums.remove(3) # {1, 4} +nums.pop() # Removes a random item +``` + +--- + +### πŸ”Ή Set Operations (Math-like) + +| Method | Description | Example | +|-----------------------------|----------------------------------|------------------------| +| `union()` or `|` | Combines two sets | `set1.union(set2)` | +| `intersection()` or `&` | Common items in both sets | `set1 & set2` | +| `difference()` or `-` | Items in set1 but not in set2 | `set1 - set2` | +| `symmetric_difference()` or `^` | Items in either set, not both | `set1 ^ set2` | + +**Example:** + +```python +A = {1, 2, 3} +B = {3, 4, 5} + +print(A | B) # {1, 2, 3, 4, 5} (union) +print(A & B) # {3} (intersection) +print(A - B) # {1, 2} (difference) +print(A ^ B) # {1, 2, 4, 5} (symmetric difference) +``` + +--- + +### πŸ”Ή Checking Relationships + +| Method | Description | Example | +|------------------|---------------------------------------|---------------------| +| `issubset()` | Checks if all items are in another set| `A.issubset(B)` | +| `issuperset()` | Checks if all items of another set are inside | `A.issuperset(B)` | +| `isdisjoint()` | Checks if two sets have no common items| `A.isdisjoint(B)` | + +**Example:** + +```python +X = {1, 2} +Y = {1, 2, 3} + +print(X.issubset(Y)) # True (X is inside Y) +print(Y.issuperset(X)) # True (Y contains X) +print(X.isdisjoint({4})) # True (no common items) +``` + +--- + +## 5. FrozenSets (Immutable Sets) + +A **frozenset** is like a set but **cannot be changed** after creation. +Useful when you need an unchangeable set (e.g., as a dictionary key). + +**Example:** + +```python +frozen = frozenset([1, 2, 3]) +# frozen.add(4) ❌ Error! Frozensets are immutable. +``` + +--- + +## 6. Advanced Topics (Hashing & Memory) + +### βœ” How Sets Work Internally (Hashing) + +- Python uses **hashing** to store set items. +- Each item gets a unique **hash value** (like a fingerprint). +- Searching in sets is very **fast** (O(1) time complexity). + +```python +print(hash("hello")) # Output: Some unique number +``` + +--- + +### βœ” Garbage Collection in Sets + +- Python **automatically** clears unused sets from memory. +- You can manually trigger garbage collection if needed: + +```python +import gc +gc.collect() +``` + +--- + +## 7. When to Use Sets? + +βœ… Remove duplicates from a list. +βœ… Fast membership testing (`if x in my_set`). +βœ… Perform mathematical set operations (union, intersection, etc.). + +**Example:** + +```python +names = ["Alice", "Bob", "Alice", "Charlie"] +unique_names = set(names) # Removes duplicates +print(unique_names) # {'Alice', 'Bob', 'Charlie'} +``` + +--- + +## 8. Final Summary + +βœ” Sets store **unique**, **unordered** items. +βœ” Use `add()`, `remove()`, `discard()` to modify sets. +βœ” Use `union()`, `intersection()`, `difference()` for math operations. +βœ” **FrozenSets** are immutable sets. +βœ” Sets are great for **removing duplicates** and **fast lookups**! + +--- + +# πŸ“š Happy Learning Python Sets! diff --git a/00_python_colab/08_modules_functions/readme.md b/00_python_colab/08_modules_functions/readme.md index 727de8d..4161fe0 100644 --- a/00_python_colab/08_modules_functions/readme.md +++ b/00_python_colab/08_modules_functions/readme.md @@ -1 +1,262 @@ -# [Lesson 08: Modules & Functions](https://colab.research.google.com/drive/1hK73zQXY_qO9xZYxpX2zVtemBWM0Rq6O?usp=sharing) +# πŸ“¦ Modules and 🍳 Functions in Python + +--- + +## πŸ“¦ MODULES in Python + +### What is a Module? +> A **module** is like a **toolbox** β€” it holds ready-made tools (functions, variables, classes) you can use anytime. + +--- + +## πŸ“‚ Types of Modules + +| Type | Description | +|:---|:---| +| πŸš€ Built-in Modules | Already available inside Python (e.g., `math`, `random`) | +| ✍️ User-created Modules | You create your own modules | +| 🌍 External Modules | Downloaded from the internet (e.g., `requests`) | + +--- + +### 1. πŸš€ Built-in Module Example +```python +import math # Import the math toolbox + +print(math.sqrt(25)) # ➑️ 5.0 +``` +🧠 **Real-life example**: Like using your calculator’s √ button. + +--- + +### 2. ✍️ User-created Module Example +Create a file `mymodule.py`: +```python +# mymodule.py +def add(a, b): + return a + b +``` +Use it in another file: +```python +import mymodule + +print(mymodule.add(5, 3)) # ➑️ 8 +``` +🧠 **Real-life example**: Like writing your own recipe. + +--- + +### 3. 🌍 External Module Example +Install first: +```bash +pip install requests +``` +Then use: +```python +import requests + +website = requests.get("https://www.example.com") +print(website.status_code) +``` +🧠 **Real-life example**: Like downloading a new cooking recipe. + +--- + +## πŸ”„ IMPORTING METHODS + +| Syntax | Usage | +|:---|:---| +| `import module` | Full access | +| `from module import item` | Import specific | +| `from module import item as alias` | Rename imported item | +| `from module import *` | Import all (not recommended) | + +Example: +```python +import math +print(math.sqrt(16)) + +from math import sqrt +print(sqrt(16)) + +from math import pi as circle_number +print(circle_number) + +from math import * +print(sqrt(36)) +``` + +--- + +# 🍳 FUNCTIONS in Python + +## What is a Function? +> A **function** is like a **recipe card** β€” follow the steps to get a result. + +--- + +## πŸ“‹ Simple Function Example +```python +def greet(): + """Says hello""" + print("Hello World!") + +greet() +``` +🧠 **Real-life example**: Like greeting someone at the door. + +--- + +## πŸ” Function With Inputs (Arguments) +```python +def make_sandwich(bread, filling="cheese"): + print(f"Making {filling} sandwich with {bread} bread") + +make_sandwich("whole wheat") +make_sandwich(filling="ham", bread="white") +``` +🧠 **Real-life example**: Ordering your sandwich. + +--- + +## πŸŽ’ Special Argument Types + +| Symbol | Meaning | +|:---|:---| +| `*args` | Multiple positional arguments | +| `**kwargs` | Multiple named arguments | + +```python +def food_report(*fruits, **prices): + print("Fruits:", fruits) + print("Prices:", prices) + +food_report("apple", "banana", apple=1.0, banana=0.5) +``` +🧠 **Real-life example**: Bag full of fruits with labels. + +--- + +## 🎯 Returning Values +```python +def calculate(num1, num2): + return num1 + num2, num1 * num2 + +sum_result, product_result = calculate(3, 4) +print(sum_result) # 7 +print(product_result) # 12 +``` +🧠 **Real-life example**: Cooking and getting two dishes from one recipe. + +--- + +## ⚑ Lambda Functions (One-Line Recipes) +```python +square = lambda x: x * x +print(square(5)) # ➑️ 25 +``` +🧠 **Real-life example**: Quick tea recipe. + +--- + +## πŸ“¦ Generator Functions (Yield Values) +```python +def count_up_to(max): + num = 1 + while num <= max: + yield num + num += 1 + +counter = count_up_to(3) + +print(next(counter)) # 1 +print(next(counter)) # 2 +print(next(counter)) # 3 +``` +🧠 **Real-life example**: Delivering pizza slice by slice. + +--- + +# 🌍 VARIABLE SCOPE + +| Type | Meaning | +|:---|:---| +| Global Variable | Accessible everywhere | +| Local Variable | Accessible inside the function only | + +```python +global_var = "I'm everywhere!" + +def test_scope(): + local_var = "I'm only here!" + print(global_var) + +test_scope() +# print(local_var) ❌ Error: local_var only inside function +``` +🧠 **Real-life example**: +- Global βž” Everyone uses it. +- Local βž” Private kitchen stock. + +--- + +# ♻️ RECURSION (Function Calling Itself) +```python +def factorial(n): + if n == 1: + return 1 + else: + return n * factorial(n-1) + +print(factorial(5)) # ➑️ 120 +``` +🧠 **Real-life example**: Russian dolls inside each other. + +--- + +# πŸ› οΈ TIPS & TRICKS + +### Type Hints +```python +def multiply(x: int, y: int) -> int: + return x * y +``` + +### Return Multiple Values +```python +def get_info() -> tuple[str, int]: + return ("Alice", 30) +``` + +### Argument Order +```python +def example(a, b=2, *c, d, **e): + pass +``` +🧠 **Order**: Normal βž” Default βž” *args βž” keyword-only βž” **kwargs + +--- + +# 🌟 Key Concepts (SUPER EASY) + +| Word | Meaning | +|:---|:---| +| Module | Ready-made toolbox | +| Function | Recipe card | +| Arguments | Ingredients you provide | +| Return | Dish you get | +| Scope | Where you can use variables | +| Recursion | Function repeating itself | +| Generator | Magic box giving items one-by-one | + +--- + +# 🧠 QUICK REMINDERS + +βœ… Use `def` to create a function +βœ… Use `return` to send back a result +βœ… Use `yield` to create a generator +βœ… Use `*args` for many items +βœ… Use `**kwargs` for many named items +βœ… Keep functions **small, simple, and focused** + diff --git a/00_python_colab/09_exception_handling/readme.md b/00_python_colab/09_exception_handling/readme.md index 253b2e1..7906cc9 100644 --- a/00_python_colab/09_exception_handling/readme.md +++ b/00_python_colab/09_exception_handling/readme.md @@ -1 +1,290 @@ -# [Lesson 09: Exception Handling](https://colab.research.google.com/drive/16hWNFjSPRhZIOQKUmuw672Md-m9aCgOi?usp=sharing) +# Python Exception Handling + +## Overview + +In Python, **exception handling** allows us to manage errors in a controlled way, preventing the program from crashing unexpectedly. This is done using blocks such as `try`, `except`, `else`, and `finally`. Proper exception handling improves the stability and robustness of a program. + +## Table of Contents + +- [Why Use Exception Handling?](#why-use-exception-handling) +- [Try Block](#1-the-try-block) +- [Except Block](#2-the-except-block) +- [Else Block](#3-the-else-block) +- [Finally Block](#4-the-finally-block) +- [Putting It All Together](#putting-it-all-together) +- [Example: Handling Errors in Real Life Code](#example-handling-errors-in-real-life-code) +- [Practice Problem](#practice-problem) +- [Throwing Exceptions in Functions](#throwing-exceptions-in-functions) +- [Custom Exceptions](#custom-exceptions) +- [Summary](#summary) + +## Why Use Exception Handling? + +1. **Prevents Crashes**: Keeps the program running even if something goes wrong. +2. **Graceful Error Recovery**: Instead of crashing, we show a helpful error message. +3. **Cleaner Code**: Helps separate error-handling logic from normal code. +4. **Resource Management**: Ensures resources (like files) are properly closed, even if there's an error. + +--- + +## 1. The Try Block + +The `try` block is where we place code that may cause an error. If an error happens, the program will jump to the `except` block. + +```python +try: + result = 10 / 0 # This will cause an error because dividing by 0 is not allowed. +except: + print("An error occurred!") +``` + +### Output: +``` +An error occurred! +``` + +--- + +## 2. The Except Block + +The `except` block handles specific errors. You can catch a specific error type (e.g., division by zero) or handle all errors. + +```python +try: + result = 10 / 0 # Trying to divide by 0. +except ZeroDivisionError: + print("Cannot divide by zero!") # This will catch the specific error of dividing by 0. +``` + +### Output: +``` +Cannot divide by zero! +``` + +--- + +## 3. The Else Block + +The `else` block runs only if there are no errors in the `try` block. It's like saying, "If everything works fine, do this." + +```python +try: + result = 10 / 2 # No error here, so the else block will run. +except ZeroDivisionError: + print("Cannot divide by zero!") +else: + print(f"Division successful. Result: {result}") # This runs only if there's no error. +``` + +### Output: +``` +Division successful. Result: 5.0 +``` + +--- + +## 4. The Finally Block + +The `finally` block always runs, no matter if there was an error or not. It's used for cleanup, like closing files or releasing resources. + +```python +try: + result = 10 / 0 # This will raise an error. +except ZeroDivisionError: + print("Cannot divide by zero!") +finally: + print("This will always execute.") # This runs no matter what. +``` + +### Output: +``` +Cannot divide by zero! +This will always execute. +``` + +--- + +## Putting It All Together + +Here’s an example that combines all four blocks. + +```python +def divide_numbers(a, b): + try: + result = a / b # Try dividing a by b. + except ZeroDivisionError: + print("Error: Cannot divide by zero!") # If dividing by 0, print this message. + except TypeError: + print("Error: Invalid input type. Numbers required.") # If the inputs aren't numbers, print this message. + else: + print(f"Division successful. Result: {result}") # If no errors, print the result. + finally: + print("Operation complete.") # This always runs, no matter what. + +# Test cases +divide_numbers(10, 2) # This will divide normally +divide_numbers(10, 0) # This will cause a division by zero error +divide_numbers(10, "2") # This will cause a type error because "2" is a string, not a number +``` + +### Output: +``` +Division successful. Result: 5.0 +Operation complete. +Error: Cannot divide by zero! +Operation complete. +Error: Invalid input type. Numbers required. +Operation complete. +``` + +--- + +## Example: Handling Errors in Real Life Code + +Here’s a more complex example that handles data generation and calculations. + +```python +import random + +def generate_random_data(num_samples): + try: + if not isinstance(num_samples, int) or num_samples <= 0: + raise ValueError("Number of samples must be a positive integer.") # Raise error if num_samples is invalid. + data = [(random.randint(1, 100), random.randint(1, 100)) for _ in range(num_samples)] # Create random data. + return data + except ValueError as ve: + print(f"Error: {ve}") # Handle ValueError (invalid input for num_samples). + return [] + except Exception as e: + print(f"An unexpected error occurred: {e}") # Handle any other unexpected errors. + return [] + +def calculate_ratios(data): + ratios = [] + try: + for num1, num2 in data: + if num2 == 0: + raise ZeroDivisionError("Cannot divide by zero.") # Handle division by zero error. + ratio = num1 / num2 # Calculate the ratio. + ratios.append(ratio) + return ratios + except ZeroDivisionError as zde: + print(f"Error: {zde}") # Handle division by zero error. + return [] + except TypeError as te: + print(f"Error: {te}") # Handle type error if data is not correct. + return [] + except Exception as e: + print(f"An unexpected error occurred: {e}") # Handle any other unexpected errors. + return [] + +def process_data(num_samples): + data = generate_random_data(num_samples) # Generate random data. + if not data: # If there was an error generating data (empty list), return empty. + return [] + return calculate_ratios(data) # Calculate ratios based on the data. + +# Example usage +results = process_data(10) # Try with valid input +if results: + print("Calculated ratios:", results) +else: + print("Data processing failed due to an error.") +``` + +### Output: +``` +Calculated ratios: [0.48, 2.3, 1.39, 2.93, 0.59, 0.8, 16.25, 0.72, 4.14, 0.92] +``` + +--- + +## Practice Problem + +Write a Python program that asks the user for two numbers and divides them. Use exception handling to catch any errors that might occur, such as division by zero or invalid input. + +```python +try: + num1 = float(input("Enter the first number: ")) # Get first number from user + num2 = float(input("Enter the second number: ")) # Get second number from user + result = num1 / num2 # Try to divide +except ValueError: # Handle invalid input errors + print("Error: Invalid input. Please enter numbers.") +except ZeroDivisionError: # Handle division by zero + print("Error: Cannot divide by zero.") +else: + print(f"The result is: {result}") # Print the result if no errors occurred +finally: + print("Thank you for using the program!") # This runs no matter what +``` + +### Output for division by zero: +``` +Enter the first number: 0 +Enter the second number: 0 +Error: Cannot divide by zero. +Thank you for using the program! +``` + +--- + +## Throwing Exceptions in Functions + +In Python, you can raise exceptions manually using the `raise` keyword. This stops the function and triggers the error. + +```python +def divide(a, b): + if b == 0: + raise ValueError("Division by zero is not allowed!") # Manually raise an error + return a / b + +try: + result = divide(5, 0) # This will raise an exception +except ValueError as e: + print(f"Error: {e}") # Catch and handle the error +``` + +### Output: +``` +Error: Division by zero is not allowed! +``` + +--- + +## Custom Exceptions + +You can create your own exception classes to handle special situations. + +```python +class NegativeNumberError(Exception): + """Custom exception for negative numbers""" + pass + +def check_positive(n): + if n < 0: + raise NegativeNumberError("Negative numbers are not allowed!") + return f"{n} is positive" + +try: + print(check_positive(-5)) # This will raise a custom error +except NegativeNumberError as e: + print(f"Custom Exception Caught: {e}") +``` + +### Output: +``` +Custom Exception Caught: Negative numbers are not allowed! +``` + +--- + +## Summary + +- **try block**: Code that might cause an error. +- **except block**: Handles the error if it occurs. +- **else block**: Runs if no errors occurred in the `try` block. +- **finally block**: Always runs, no matter what. +- **raise**: Used to manually throw an error from a function. +- **Custom Exceptions**: You can create your own error types to handle special cases in your program. + +