Logo

🐍 What is Python?

📌 2. History and Background

Python was developed in the late 1980s by Guido van Rossum at the National Research Institute for Mathematics and Computer Science in the Netherlands. The language was named after the British comedy group Monty Python.

📌 3. Key Features of Python

  • Simple and Easy to Learn: Python has a simple syntax similar to English
  • Interpreted: Python code is executed line by line, making debugging easier
  • Cross-platform: Runs on Windows, macOS, Linux, and more
  • Large Standard Library: Comes with extensive built-in modules
  • Object-Oriented: Supports object-oriented programming concepts

📌 4. What is Python Used For?

  • Web Development (Django, Flask)
  • Data Science and Analytics
  • Machine Learning and AI
  • Automation and Scripting
  • Desktop Applications
  • Scientific Computing

📌 5. Python 2 vs Python 3

✅ Today, always use Python 3.x.

Python 2 reached end-of-life on January 1, 2020, and is no longer supported. Python 3 has many improvements and new features.

📌 6. Advantages of Python

  • Simple syntax makes it easy to write and debug
  • Rapid development – fewer lines of code compared to other languages
  • Large ecosystem of third-party libraries (PyPI)
  • Strong support for integration with other languages and tools
  • Popular in academia, industry, and research

📌 7. Disadvantages of Python

  • Slower than compiled languages like C/C++
  • Not ideal for mobile app development
  • High memory usage compared to low-level languages
  • Limited in multithreading due to the Global Interpreter Lock (GIL)

Practice Editor

Python Editor
Output

🐍 Getting Started with Python

📌 2. Installing Python

✅ Official Website:

Download Python from: 👉 https://www.python.org/downloads/

📦 Steps:

  1. Choose the version (always go for the latest Python 3.x)
  2. During installation:
    • Check the box "Add Python to PATH"
    • Click Install Now

✅ Verify Installation:

Open your terminal (CMD, PowerShell, or Bash):

python --version

or

python3 --version

📌 4. Python File Basics

  • Python files end with .py
  • To run a script:
python yourfile.py

🐍 Python Syntax: The Basics

📌 2. Comments

Used to explain code. They are ignored by Python.

# This is a single-line comment

"""
This is a 
multi-line comment
"""

📌 3. Print Statement

Used to display output.

print("Hello, World!")

📌 4. Variables and Data Types

No need to declare data types; Python is dynamically typed.

x = 10        # Integer
name = "Ali"  # String
pi = 3.14     # Float
flag = True   # Boolean

📌 5. Input

Get user input.

name = input("Enter your name: ")
print("Hello", name)

📌 6. Data Types and Casting

int("10")       # Converts string to integer
str(123)        # Converts integer to string
float("3.14")   # Converts string to float

📌 7. Conditional Statements

x = 10
if x > 5:
    print("Greater")
elif x == 5:
    print("Equal")
else:
    print("Smaller")

📌 8. Loops

🔹 for Loop

for i in range(5):
    print(i)  # Prints 0 to 4

🔹 while Loop

i = 0
while i < 5:
    print(i)
    i += 1

📌 9. Functions

def greet(name):
    print("Hello", name)

greet("Aisha")

📌 10. Operators

# Arithmetic operators
+ - * / % ** //

# Comparison operators  
== != > < >= <=

# Logical operators
and or not

📌 12. List Example

fruits = ["apple", "banana"]
fruits.append("mango")
print(fruits[1])  # banana

📝 Python Comments

🔹 1. Single-Line Comments

Use the # symbol. Everything after # on that line is ignored by Python.

# This is a single-line comment
print("Hello")  # This prints Hello

🔹 2. Multi-Line Comments (Docstrings or Block Comments)

Python doesn't have official multi-line comments, but you can:

Method 1: Use multiple #

# This is a comment
# that spans multiple
# lines

Method 2: Use triple quotes (''' or """)

(These are technically multi-line strings, often used for documentation.)

"""
This is a multi-line comment
or docstring, ignored by Python
if not assigned to a variable.
"""
print("Hi")

💡 Triple quotes are mainly used for docstrings in functions, classes, and modules.

🔹 3. Docstrings (Documentation Strings)

A docstring is a special kind of comment used to describe a function, class, or module. It goes right after the def, class, or top of a file.

def greet(name):
    """This function greets the user by name."""
    print("Hello", name)

# Access it with:
print(greet.__doc__)

🧠 Why Use Comments?

  • To explain why something is done
  • To clarify complex code
  • To make your code readable and maintainable

🚫 What Not to Do with Comments

Don't over-comment obvious code:

x = 5  # Set x to 5  ❌ (Too obvious)

Don't use comments to justify bad code. Instead, refactor the code.

📝 Python Variables

🔹 1. Declaring a Variable

Python does not require you to declare the type of variable. Just assign a value using =.

x = 5              # Integer
name = "Alice"     # String
price = 19.99      # Float
is_valid = True    # Boolean

🔹 2. Variable Naming Rules

✅ Valid names:

  • Start with a letter or underscore _
  • Followed by letters, digits, or underscores
  • Case-sensitive (name and Name are different)

❌ Invalid names:

2name = "Ali"      # ❌ Cannot start with a digit
user-name = "Ali"  # ❌ Hyphens not allowed

✅ Valid examples:

user_name = "Ali"
_user = "hidden"
Name1 = "John"

🔹 3. Data Types Stored in Variables

integer = 42
float_num = 3.14
string = "Hello"
boolean = True
list_var = [1, 2, 3]
dict_var = {"key": "value"}

🔹 4. Checking the Type of a Variable

x = 10
print(type(x))    # Output: <class 'int'>

🔹 5. Multiple Assignments

You can assign multiple variables at once:

a, b, c = 1, 2, 3
print(a, b, c)  # Output: 1 2 3

# Assigning the same value to multiple variables:
x = y = z = 0

🔹 6. Constants (By Convention)

Python doesn't have true constants, but you can use uppercase names to indicate a value shouldn't change.

PI = 3.14159
MAX_USERS = 100

🔒 These can still be changed in code, but shouldn't be.

🔹 7. Type Casting (Changing Variable Types)

x = str(10)       # '10'
y = int("5")      # 5
z = float("3.14") # 3.14

🔹 8. Deleting a Variable

x = 10
del x

Trying to use x after this will give an error.

🧠 What Are Data Types in Python?

🔹 1. Basic (Built-in) Data Types

🔸 int – Integer

a = 100
print(type(a))  # <class 'int'>

🔸 float – Decimal / Floating Point

pi = 3.14159
print(type(pi))  # <class 'float'>

🔸 str – String

name = "Alice"
print(type(name))  # <class 'str'>

🔸 bool – Boolean

is_online = True
print(type(is_online))  # <class 'bool'>

🔹 2. Collection Data Types

🔸 list – Mutable Sequence

fruits = ["apple", "banana", "cherry"]
print(type(fruits))  # <class 'list'>

🔸 tuple – Immutable Sequence

point = (10, 20)
print(type(point))  # <class 'tuple'>

🔸 set – Unique, Unordered Collection

colors = {"red", "green", "blue"}
print(type(colors))  # <class 'set'>

🔸 dict – Dictionary (Key:Value Pairs)

student = {"name": "Ali", "age": 21}
print(type(student))  # <class 'dict'>

🔹 3. None Type

Represents the absence of a value.

x = None
print(type(x))  # <class 'NoneType'>

🔹 4. Type Conversion (Casting)

Convert one type into another:

int("10")      # 10
str(99)        # "99"
float("3.14")  # 3.14
bool(1)        # True

🔹 5. Checking the Type

a = 10
print(type(a))  # <class 'int'>

🔢 Python Numbers

🔹 1. Integer (int)

Whole numbers without decimals. Can be positive or negative.

a = 100
b = -25
print(type(a))  # <class 'int'>

🔹 2. Float (float)

Numbers with decimal points. Used for measurements, prices, etc.

pi = 3.14159
temperature = -5.5
print(type(pi))  # <class 'float'>

🔹 3. Complex (complex)

Numbers with a real and imaginary part (a + bj). j is the imaginary unit in Python (like i in math).

z = 2 + 3j
print(type(z))  # <class 'complex'>

🔸 4. Type Conversion (Casting)

You can convert between number types using:

int(3.9)      # 3
float(5)      # 5.0
complex(4)    # (4+0j)

🔸 5. Number Operations

Python supports arithmetic operations:

a = 15
b = 4

print(f"Addition: {a + b}")        # 19
print(f"Subtraction: {a - b}")     # 11
print(f"Multiplication: {a * b}")  # 60
print(f"Division: {a / b}")        # 3.75
print(f"Floor division: {a // b}") # 3
print(f"Modulus: {a % b}")         # 3
print(f"Exponentiation: {a ** b}") # 50625

🔸 6. Built-in Number Functions

x = -5.7
print(abs(x))      # 5.7 (absolute value)
print(round(x))    # -6 (round to nearest integer)
print(max(1, 2, 3)) # 3 (maximum value)
print(min(1, 2, 3)) # 1 (minimum value)
print(pow(2, 3))   # 8 (2 to the power of 3)

🔸 7. Using the math Module

Python's math module gives you access to advanced mathematical functions:

import math

print(math.sqrt(16))       # 4.0
print(math.factorial(5))   # 120
print(math.pi)             # 3.141592...
print(math.ceil(2.3))      # 3
print(math.floor(2.7))     # 2

🔄 What is Python Casting?

🔹 1. Casting to int

Used to convert float or string to an integer. It removes the decimal part.

x = int(3.9)        # 3
y = int("10")       # 10
z = int(True)       # 1

# Invalid
# int("hello") → Error

🔹 2. Casting to float

Used to convert int or string to a float (decimal).

a = float(5)        # 5.0
b = float("7.25")   # 7.25
c = float(False)    # 0.0

🔹 3. Casting to str

Used to convert any type (int, float, bool) into a string.

name = str(123)       # "123"
price = str(99.99)    # "99.99"
flag = str(True)      # "True"

🔹 4. Casting to bool

Used to convert values to True or False:

print(bool(1))        # True
print(bool(0))        # False
print(bool("hi"))     # True
print(bool(""))       # False

🔸 5. Common Mistakes in Casting

int("3.5")     # ❌ Error (you must use float first)
float("abc")   # ❌ Error (can't convert letters to numbers)
int("five")    # ❌ Error (not a number string)

# ✅ For example:
x = int(float("3.5"))   # ✅ 3

🔹 6. Automatic Type Conversion (Implicit)

Python sometimes converts types automatically:

x = 5         # int
y = 2.0       # float
result = x + y # Result will be float (7.0)
print(result)  # 7.0

📋 Python Lists

🎯 Understanding Lists

Lists are one of the most fundamental and versatile data structures in Python. They are ordered, mutable collections that can store multiple items of different types. Think of a list as a container that holds items in a specific order, where you can add, remove, or modify items as needed.

📊 Characteristics

  • Ordered: Items maintain their position
  • Mutable: Can be changed after creation
  • Allow duplicates: Same value can appear multiple times
  • Mixed types: Can store different data types

🎪 Common Uses

  • Storing collections of data
  • Managing to-do items
  • Keeping track of scores or measurements
  • Building dynamic data structures

🏋️ Practice: List Mastery

Python Editor
Output

📚 Quick Reference

Creating Lists:
  • my_list = [1, 2, 3] - With initial values
  • empty = [] - Empty list
  • repeated = [0] * 5 - Repeated values
  • from_range = list(range(1, 6)) - From range
Adding Items:
  • list.append(item) - Add to end
  • list.insert(index, item) - Insert at position
  • list.extend(other_list) - Add multiple items
  • list1 + list2 - Combine lists
Removing Items:
  • list.remove(value) - Remove by value
  • list.pop(index) - Remove by index
  • del list[index] - Delete by index
  • list.clear() - Remove all items
Common Operations:
  • len(list) - Get length
  • item in list - Check membership
  • list.count(item) - Count occurrences
  • list.index(item) - Find index
  • list.sort() - Sort in place
  • sorted(list) - Return sorted copy

📚 Python Dictionaries

Creating Dictionaries

Dictionaries store data in key-value pairs and are unordered, changeable, and indexed:

Dictionary Methods

Practice: Dictionary Operations

Python Editor
Output

📦 Python Tuples

Practice: Working with Tuples

Python Editor
Output

🎯 Python Sets

Practice: Set Operations

Python Editor
Output

🎯 If...Else Statements

Practice: Conditional Logic

Python Editor
Output

🔄 While Loops

Practice: While Loops

Python Editor
Output

🔁 For Loops

Practice: For Loops

Python Editor
Output

🎯 Python Functions

Practice: Functions

Python Editor
Output

📦 Function Arguments

Practice: Function Arguments

Python Editor
Output

🌐 Variable Scope

Practice: Variable Scope

Python Editor
Output

📦 Python Modules

Practice: Using Modules

Python Editor
Output

⚠️ Exception Handling

Practice: Exception Handling

Python Editor
Output

🚀 Practice Projects

Your Turn: Create a Project

Python Editor
Output

📚 Python Dictionaries

Creating Dictionaries

Dictionaries store data in key-value pairs and are unordered, changeable, and indexed:

Dictionary Methods

Practice: Dictionary Operations

Python Editor
Output

📦 Python Tuples

Practice: Working with Tuples

Python Editor
Output

🎯 Python Sets

Practice: Set Operations

Python Editor
Output

🎯 If...Else Statements

Practice: Conditional Logic

Python Editor
Output

🔄 While Loops

⚠️ Common While Loop Pitfalls

# PITFALL 1: Infinite loop (forgot to update condition)
# count = 5
# while count > 0:
#     print("This will run forever!")
#     # Forgot: count -= 1

# PITFALL 2: Off-by-one errors
print("Correct way:")
i = 0
while i < 3:  # Runs 3 times (0, 1, 2)
    print(f"i = {i}")
    i += 1

# PITFALL 3: Modifying the wrong variable
target_sum = 100
current_sum = 0
num = 1
while current_sum < target_sum:
    current_sum += num
    num += 1  # Make sure to increment the right variable
    
print(f"Reached sum: {current_sum}")

Practice: While Loops

Python Editor
Output

🔁 For Loops

Practice: For Loops

Python Editor
Output

🎯 Python Functions

Practice: Functions

Python Editor
Output

📦 Function Arguments

Practice: Function Arguments

Python Editor
Output

👁️ Variable Scope

Practice: Variable Scope

Python Editor
Output

📦 Python Modules

📚 Popular Standard Library Modules

# datetime - Working with dates and times
from datetime import datetime, timedelta
now = datetime.now()
tomorrow = now + timedelta(days=1)
print(f"Today: {now.strftime('%Y-%m-%d %H:%M:%S')}")
print(f"Tomorrow: {tomorrow.strftime('%Y-%m-%d')}")

# random - Generate random numbers and choices
import random
print(f"Random integer: {random.randint(1, 100)}")
print(f"Random float: {random.random()}")
colors = ['red', 'green', 'blue', 'yellow']
random.shuffle(colors)
print(f"Shuffled colors: {colors}")

# os - Operating system interface
import os
print(f"Current directory: {os.getcwd()}")
print(f"Environment variable PATH exists: {'PATH' in os.environ}")

# json - Working with JSON data
import json
data = {"name": "Alice", "age": 30, "city": "New York"}
json_string = json.dumps(data)
parsed_data = json.loads(json_string)
print(f"JSON: {json_string}")
print(f"Parsed name: {parsed_data['name']}")

# re - Regular expressions
import re
text = "My phone number is 123-456-7890"
phone_pattern = r'\d{3}-\d{3}-\d{4}'
match = re.search(phone_pattern, text)
if match:
    print(f"Found phone number: {match.group()}")

# collections - Specialized container types
from collections import Counter, defaultdict
words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']
word_count = Counter(words)
print(f"Word frequencies: {word_count}")
print(f"Most common: {word_count.most_common(2)}")

Practice: Working with Modules

Python Editor
Output

⚠️ Exception Handling

🎯 Understanding Exceptions

Exception handling is a crucial programming concept that allows you to gracefully handle errors and unexpected situations in your code. Instead of letting your program crash, you can catch errors and respond appropriately.

🛡️ What are Exceptions?

Exceptions are events that disrupt the normal flow of program execution. They occur when Python encounters an error it cannot handle.

💡 Why Handle Exceptions?

Proper exception handling prevents crashes, provides better user experience, and allows for graceful error recovery.

🎯 Common Exception Types

Python has many built-in exception types like ValueError, TypeError, FileNotFoundError, and more.

🎯 Multiple Exception Types

You can handle multiple exception types in a single except block or use multiple except blocks:

# Method 1: Multiple exceptions in one block
try:
    value = int(input("Enter a number: "))
    result = 100 / value
    items = [1, 2, 3]
    print(items[value])
except (ValueError, ZeroDivisionError, IndexError) as e:
    print(f"An error occurred: {e}")

# Method 2: Separate except blocks
try:
    value = int(input("Enter a number: "))
    result = 100 / value
except ValueError:
    print("Invalid input! Please enter a number.")
except ZeroDivisionError:
    print("Cannot divide by zero!")
except Exception as e:
    print(f"Unexpected error: {e}")

🔗 Else and Finally Clauses

The else clause runs when no exception occurs, and finally always executes:

def safe_divide(a, b):
    try:
        result = a / b
    except ZeroDivisionError:
        print("Cannot divide by zero!")
        return None
    except TypeError:
        print("Both arguments must be numbers!")
        return None
    else:
        # Executes only if no exception occurred
        print("Division successful!")
        return result
    finally:
        # Always executes
        print("Division operation completed.")

# Examples
print(safe_divide(10, 2))    # Successful division
print(safe_divide(10, 0))    # Division by zero
print(safe_divide(10, "2"))  # Type error

🚀 Raising Custom Exceptions

You can raise your own exceptions using the raise statement:

def validate_age(age):
    if age < 0:
        raise ValueError("Age cannot be negative!")
    elif age > 150:
        raise ValueError("Age seems unrealistic!")
    elif not isinstance(age, int):
        raise TypeError("Age must be an integer!")
    return f"Age {age} is valid."

# Test the function
try:
    print(validate_age(25))      # Valid
    print(validate_age(-5))      # Raises ValueError
    print(validate_age("25"))    # Raises TypeError
except ValueError as e:
    print(f"Value Error: {e}")
except TypeError as e:
    print(f"Type Error: {e}")

🏗️ Custom Exception Classes

Create your own exception classes for specific error scenarios:

# Custom exception classes
class BankAccountError(Exception):
    """Base exception for bank account operations"""
    pass

class InsufficientFundsError(BankAccountError):
    """Raised when account has insufficient funds"""
    def __init__(self, balance, amount):
        self.balance = balance
        self.amount = amount
        super().__init__(f"Insufficient funds: ${balance} < ${amount}")

class InvalidAccountError(BankAccountError):
    """Raised when account number is invalid"""
    pass

class BankAccount:
    def __init__(self, account_number, balance=0):
        if len(str(account_number)) != 6:
            raise InvalidAccountError("Account number must be 6 digits")
        self.account_number = account_number
        self.balance = balance
    
    def withdraw(self, amount):
        if amount > self.balance:
            raise InsufficientFundsError(self.balance, amount)
        self.balance -= amount
        return self.balance

# Using custom exceptions
try:
    account = BankAccount(123456, 100)
    account.withdraw(150)  # This will raise InsufficientFundsError
except InsufficientFundsError as e:
    print(f"Transaction failed: {e}")
except InvalidAccountError as e:
    print(f"Account error: {e}")

🔍 Exception Information

You can access detailed information about exceptions:

import traceback
import sys

def risky_function():
    try:
        # Simulate various errors
        data = [1, 2, 3]
        index = int(input("Enter index: "))
        print(f"Value at index {index}: {data[index]}")
        
        divisor = int(input("Enter divisor: "))
        result = data[index] / divisor
        print(f"Result: {result}")
        
    except Exception as e:
        # Get exception details
        exc_type, exc_value, exc_traceback = sys.exc_info()
        
        print(f"Exception Type: {type(e).__name__}")
        print(f"Exception Message: {str(e)}")
        print(f"Exception Args: {e.args}")
        
        # Print full traceback
        print("\nFull Traceback:")
        traceback.print_exc()

# Test the function
risky_function()

💡 Best Practices & Common Patterns

Follow these best practices for effective exception handling:

# 1. Be specific with exception types
try:
    value = int(input("Enter number: "))
except ValueError:  # Specific, not just Exception
    print("Invalid number format")

# 2. Use context managers for resource management
try:
    with open("data.txt", "r") as file:
        content = file.read()
except FileNotFoundError:
    print("File not found")
# File automatically closed even if exception occurs

# 3. Log exceptions for debugging
import logging

def process_data(data):
    try:
        result = complex_calculation(data)
        return result
    except Exception as e:
        logging.error(f"Error processing data: {e}", exc_info=True)
        raise  # Re-raise the exception

# 4. Validate input early
def calculate_interest(principal, rate, time):
    # Validate inputs
    if not all(isinstance(x, (int, float)) for x in [principal, rate, time]):
        raise TypeError("All parameters must be numbers")
    if principal < 0 or rate < 0 or time < 0:
        raise ValueError("All parameters must be non-negative")
    
    return principal * rate * time / 100

# 5. Use finally for cleanup
def database_operation():
    connection = None
    try:
        connection = connect_to_database()
        perform_operation(connection)
    except DatabaseError as e:
        print(f"Database error: {e}")
    finally:
        if connection:
            connection.close()  # Always close connection

📋 Exception Handling Quick Reference

Common Built-in Exceptions:
  • ValueError - Invalid value for operation
  • TypeError - Wrong data type
  • IndexError - Index out of range
  • KeyError - Dictionary key not found
  • FileNotFoundError - File doesn't exist
  • ZeroDivisionError - Division by zero
  • ImportError - Module import failed
  • AttributeError - Attribute doesn't exist
Exception Hierarchy:
  • BaseException - Base for all exceptions
  • Exception - Base for regular exceptions
  • ArithmeticError - Base for math errors
  • LookupError - Base for lookup errors
  • OSError - Operating system errors
Best Practices:
  • Catch specific exceptions, not general Exception
  • Use finally for cleanup code
  • Don't ignore exceptions silently
  • Log exceptions for debugging
  • Use context managers for resources
  • Validate input early in functions
  • Create custom exceptions for specific domains

🏃‍♂️ Practice Exercise

Try creating a robust calculator that handles various types of errors:

Click "Run Code" to test your exception handling!

🏗️ Practice Projects

📚 Additional Resources