Friday, October 9, 2026

Python Algorithms

 

Python Algorithms for Beginners – Searching, Sorting and Essential Problem-Solving Techniques

Learn Linear Search, Binary Search, Sorting Algorithms, Frequency Counting, Prime Numbers, Fibonacci, GCD, LCM, Palindromes and Anagrams with Python

Have you ever wondered how a computer finds a name in a list of thousands of students, arranges marks from highest to lowest, or checks whether a number is prime?

The secret lies in algorithms!

In this Python Pebbles tutorial, we will explore some of the most useful algorithms that every Class 9–12 student should understand. You will learn not only how to write the code but also how to think like a programmer.

1. What Is an Algorithm?

An algorithm is a step-by-step procedure used to solve a problem.

Think of an algorithm like a recipe. A recipe explains how to prepare a dish step by step. Similarly, an algorithm explains how to solve a programming problem step by step.

Example: Finding the Largest Number

Suppose we have these numbers:

numbers = [12, 45, 7, 89, 34]

We want to find the largest number.

Our algorithm is:

  1. Assume the first number is the largest.

  2. Compare it with every other number.

  3. If a larger number is found, update the largest value.

  4. Display the result.

Python program:

numbers = [12, 45, 7, 89, 34]

largest = numbers[0]

for number in numbers:
    if number > largest:
        largest = number

print("Largest number:", largest)

Output:

Largest number: 89

Python Pebble: Before writing code, explain the solution in simple steps. This makes programming easier and helps you find mistakes.


Part 1: Searching Algorithms

Searching means finding whether a particular value exists in a collection and, if it does, where it is located.

Imagine looking for your name in a class attendance list. The method you use depends on how the list is organized.

2. Linear Search

Linear Search checks each element one by one until the target is found or the list ends.

It works on both sorted and unsorted lists.

Example

numbers = [15, 28, 7, 42, 19]
target = 42

found = False

for i in range(len(numbers)):
    if numbers[i] == target:
        print("Found at index:", i)
        found = True
        break

if not found:
    print("Number not found")

Output:

Found at index: 3

Remember that Python list indexing starts from 0.

How does it work?

For the list [15, 28, 7, 42, 19], searching for 42 follows these steps:

StepValue checkedResult
115Not found
228Not found
37Not found
442Found!

Linear Search Using a Function

def linear_search(numbers, target):
    for i in range(len(numbers)):
        if numbers[i] == target:
            return i
    return -1

data = [10, 20, 30, 40, 50]

print(linear_search(data, 30))
print(linear_search(data, 90))

Output:

2
-1

Here, -1 indicates that the target was not found.

Time complexity: O(n)O(n) in the worst case, because every element may need to be checked.

When should you use Linear Search?

  • When the list is small.

  • When the data is not sorted.

  • When you need a simple search method.

3. Binary Search

Binary Search is a faster searching algorithm, but it requires the list to be sorted.

Instead of checking every element, it repeatedly divides the search area into two halves.

Imagine searching for a word in a dictionary. You would open the dictionary near the middle rather than reading every word from the beginning.

Example

Consider this sorted list:

numbers = [10, 20, 30, 40, 50, 60, 70]

We want to find 60.

  1. Check the middle element: 40.

  2. Since 60 is greater than 40, ignore the left half.

  3. Check the middle of the remaining section.

  4. Find 60.

Python Program

def binary_search(numbers, target):
    low = 0
    high = len(numbers) - 1

    while low <= high:
        mid = (low + high) // 2

        if numbers[mid] == target:
            return mid
        elif numbers[mid] < target:
            low = mid + 1
        else:
            high = mid - 1

    return -1

data = [10, 20, 30, 40, 50, 60, 70]

print(binary_search(data, 60))
print(binary_search(data, 25))

Output:

5
-1

Linear Search vs Binary Search

FeatureLinear SearchBinary Search
Data must be sorted?NoYes
Basic methodCheck one by oneDivide the search range
Worst-case timeO(n)O(n)O(log⁡n)O(\log n)
Best suited forSmall or unsorted dataLarge, sorted data

Python Pebble: Binary Search is powerful because each step removes approximately half of the remaining search area.


Part 2: Sorting Algorithms

Sorting means arranging data in a particular order, such as ascending or descending.

For example:

Before sorting: [45, 12, 89, 23, 7]
After sorting:  [7, 12, 23, 45, 89]

Let's explore three classic sorting algorithms.

4. Bubble Sort

Bubble Sort compares adjacent elements and swaps them if they are in the wrong order.

After each complete pass through the list, the largest unsorted element moves to its correct position at the end.

Example

numbers = [5, 3, 8, 2]

for i in range(len(numbers)):
    for j in range(0, len(numbers) - i - 1):
        if numbers[j] > numbers[j + 1]:
            numbers[j], numbers[j + 1] = (
                numbers[j + 1], numbers[j]
            )

print(numbers)

Output:

[2, 3, 5, 8]

Understanding the First Pass

Starting list:

[5, 3, 8, 2]

Compare 5 and 3, then swap:

[3, 5, 8, 2]

Compare 5 and 8. No swap is needed.

Compare 8 and 2, then swap:

[3, 5, 2, 8]

The largest value, 8, has moved to the end.

Optimized Bubble Sort

We can stop early if a complete pass makes no swaps.

def bubble_sort(numbers):
    n = len(numbers)

    for i in range(n):
        swapped = False

        for j in range(n - i - 1):
            if numbers[j] > numbers[j + 1]:
                numbers[j], numbers[j + 1] = (
                    numbers[j + 1], numbers[j]
                )
                swapped = True

        if not swapped:
            break

    return numbers

print(bubble_sort([9, 4, 6, 2, 1]))

Output:

[1, 2, 4, 6, 9]

Worst-case time complexity: O(n2)O(n^2).

Use Bubble Sort to learn how comparisons, loops, and swaps work. For large real-world lists, Python's built-in sorting is generally a better choice.

5. Selection Sort

Selection Sort repeatedly finds the smallest element in the unsorted part of the list and places it at the beginning of that part.

Example

numbers = [29, 10, 14, 37, 13]

for i in range(len(numbers)):
    min_index = i

    for j in range(i + 1, len(numbers)):
        if numbers[j] < numbers[min_index]:
            min_index = j

    numbers[i], numbers[min_index] = (
        numbers[min_index], numbers[i]
    )

print(numbers)

Output:

[10, 13, 14, 29, 37]

How does it work?

  • Find the smallest number in the entire list.

  • Place it at index 0.

  • Find the smallest number in the remaining unsorted section.

  • Place it at index 1.

  • Repeat until the list is sorted.

Worst-case time complexity: O(n2)O(n^2).

Key idea: Selection Sort selects the smallest remaining element on every pass.

6. Insertion Sort

Insertion Sort builds a sorted section one element at a time.

Think about arranging playing cards in your hand. You pick up one card and insert it into the correct position among the cards you are already holding.

Python Program

numbers = [8, 4, 6, 2, 5]

for i in range(1, len(numbers)):
    key = numbers[i]
    j = i - 1

    while j >= 0 and numbers[j] > key:
        numbers[j + 1] = numbers[j]
        j -= 1

    numbers[j + 1] = key

print(numbers)

Output:

[2, 4, 5, 6, 8]

How does it work?

  1. Treat the first element as sorted.

  2. Pick the next element as key.

  3. Move larger elements one position to the right.

  4. Insert the key into the empty position.

  5. Continue until every element is processed.

Time complexity:

  • Best case: O(n)O(n), when the list is already sorted.

  • Worst case: O(n2)O(n^2), when the list is in reverse order.

Compare the Three Sorting Algorithms

AlgorithmMain ideaWorst-case time
Bubble SortSwap adjacent elementsO(n2)O(n^2)
Selection SortSelect the smallest remaining valueO(n2)O(n^2)
Insertion SortInsert each value into the sorted sectionO(n2)O(n^2)

7. Python's Built-in sort()

You do not always need to write a sorting algorithm yourself. Python provides a highly optimized sorting method.

The sort() method changes the original list.

marks = [78, 92, 65, 88, 71]

marks.sort()

print(marks)

Output:

[65, 71, 78, 88, 92]

Sorting in Descending Order

marks = [78, 92, 65, 88, 71]

marks.sort(reverse=True)

print(marks)

Output:

[92, 88, 78, 71, 65]

8. Python's sorted() Function

The sorted() function returns a new sorted list and leaves the original collection unchanged.

numbers = [40, 10, 30, 20]

result = sorted(numbers)

print("Original:", numbers)
print("Sorted:", result)

Output:

Original: [40, 10, 30, 20]
Sorted: [10, 20, 30, 40]

Difference Between sort() and sorted()

Featuresort()sorted()
TypeList methodBuilt-in function
Changes original list?YesNo
ReturnsNoneA new sorted list
Works with tuples?No, not as a tuple methodYes

9. Custom Sorting

Sometimes we want to sort data according to a special rule.

For example, suppose we have student names and marks. We want to sort the students by marks in descending order.

students = [
    ("Aman", 85),
    ("Riya", 92),
    ("Karan", 78),
    ("Meena", 92)
]

students.sort(key=lambda student: student[1], reverse=True)

print(students)

Output:

[('Riya', 92), ('Meena', 92), ('Aman', 85), ('Karan', 78)]

Here:

  • student[0] represents the student's name.

  • student[1] represents the student's marks.

  • key=lambda student: student[1] tells Python to sort using marks.

Sorting by Name

students = [
    ("Aman", 85),
    ("Riya", 92),
    ("Karan", 78)
]

result = sorted(students, key=lambda student: student[0])

print(result)

Output:

[('Aman', 85), ('Karan', 78), ('Riya', 92)]

Python Pebble: Custom sorting is useful when working with student records, product prices, employee details, and competition results.


Part 3: Common Algorithms Every Student Should Know

10. Finding the Maximum and Minimum

Python provides max() and min() for finding the largest and smallest values.

numbers = [45, 12, 89, 23, 7]

print("Maximum:", max(numbers))
print("Minimum:", min(numbers))

Output:

Maximum: 89
Minimum: 7

Find Them Without Built-in Functions

numbers = [45, 12, 89, 23, 7]

largest = numbers[0]
smallest = numbers[0]

for number in numbers:
    if number > largest:
        largest = number

    if number < smallest:
        smallest = number

print("Maximum:", largest)
print("Minimum:", smallest)

Output:

Maximum: 89
Minimum: 7

This approach helps you understand how algorithms work internally.

11. Finding Sum and Average

The sum is the total of all values. The average is the sum divided by the number of values.

Average=Sum of valuesNumber of values\text{Average}=\frac{\text{Sum of values}}{\text{Number of values}}

Python Program

marks = [80, 75, 90, 85, 70]

total = 0

for mark in marks:
    total += mark

average = total / len(marks)

print("Total:", total)
print("Average:", average)

Output:

Total: 400
Average: 80.0

Python also provides sum():

marks = [80, 75, 90, 85, 70]

print(sum(marks))
print(sum(marks) / len(marks))

Output:

400
80.0

Always check that a list is not empty before calculating its average, because division by zero is not allowed.

12. Frequency Counting

Frequency counting tells us how many times each value appears in a collection.

Suppose we want to count the votes received by candidates.

votes = ["A", "B", "A", "C", "B", "A"]

frequency = {}

for vote in votes:
    if vote in frequency:
        frequency[vote] += 1
    else:
        frequency[vote] = 1

print(frequency)

Output:

{'A': 3, 'B': 2, 'C': 1}

A Shorter Method Using Counter

from collections import Counter

votes = ["A", "B", "A", "C", "B", "A"]

frequency = Counter(votes)

print(frequency)
print(frequency["A"])

Output:

Counter({'A': 3, 'B': 2, 'C': 1})
3

Where is frequency counting useful?

  • Counting votes.

  • Counting words in an article.

  • Analyzing examination scores.

  • Finding the most common item in a dataset.

13. Duplicate Detection

A duplicate is a value that appears more than once.

Example

numbers = [10, 20, 30, 20, 40, 10, 50]

seen = set()
duplicates = set()

for number in numbers:
    if number in seen:
        duplicates.add(number)
    else:
        seen.add(number)

print("Duplicates:", sorted(duplicates))

Output:

Duplicates: [10, 20]

How does it work?

  • seen stores values that have already appeared.

  • If a value appears again, it is added to duplicates.

  • A set stores each distinct value only once.

For typical integer or string data, set membership checks are O(1)O(1) on average, so this is generally efficient.

14. Checking Prime Numbers

A prime number is a whole number greater than 1 that has exactly two positive divisors: 1 and itself.

Examples: 2, 3, 5, 7, 11, 13

Numbers such as 4, 6, 8, 9, 10 are not prime.

Python Program

def is_prime(n):
    if n < 2:
        return False

    for i in range(2, int(n ** 0.5) + 1):
        if n % i == 0:
            return False

    return True

print(is_prime(17))
print(is_prime(21))

Output:

True
False

Why do we check only up to the square root?

If a number has a factor greater than its square root, it must also have a corresponding factor smaller than its square root. Therefore, if no divisor is found up to the square root, the number is prime.

Python Pebble: The % operator gives the remainder. If n % i == 0, then i divides n exactly.

15. Generating Fibonacci Numbers

The Fibonacci sequence is a sequence in which each new number is the sum of the previous two numbers.

A common starting sequence is:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34

Python Program

n = 10

a = 0
b = 1

for i in range(n):
    print(a, end=" ")
    a, b = b, a + b

Output:

0 1 1 2 3 5 8 13 21 34

Understanding the Update

a, b = b, a + b

Python evaluates the right-hand side first, then assigns both values together.

This means:

  • The new a becomes the old b.

  • The new b becomes the sum of the old a and b.

This iterative approach avoids the repeated work of a simple recursive Fibonacci program.

16. Calculating Factorial

The factorial of a non-negative integer is the product of all positive integers up to that number.

It is represented by an exclamation mark.

5!=5×4×3×2×1=1205! = 5 \times 4 \times 3 \times 2 \times 1 = 120

By definition, 0!=10! = 1.

Python Program

n = 5
factorial = 1

for i in range(1, n + 1):
    factorial *= i

print("Factorial:", factorial)

Output:

Factorial: 120

Factorial Using a Function

def factorial(n):
    if n < 0:
        return None

    result = 1

    for i in range(1, n + 1):
        result *= i

    return result

print(factorial(5))
print(factorial(0))
print(factorial(-2))

Output:

120
1
None

The function returns None for negative input because factorial is not defined for negative integers in this context.

17. Finding GCD and LCM

What is GCD?

The Greatest Common Divisor (GCD) of two integers is the largest positive integer that divides both of them exactly.

For example, the GCD of 12 and 18 is 6.

What is LCM?

The Least Common Multiple (LCM) of two positive integers is the smallest positive integer divisible by both.

For example, the LCM of 12 and 18 is 36.

GCD Using Euclid's Algorithm

Euclid's algorithm repeatedly replaces a pair of numbers with the smaller number and their remainder until the remainder becomes zero.

def gcd(a, b):
    while b != 0:
        a, b = b, a % b

    return abs(a)

print(gcd(12, 18))
print(gcd(48, 18))

Output:

6
6

LCM Using GCD

For positive integers aa and bb:

LCM(a,b)=a×bGCD(a,b)\text{LCM}(a,b)=\frac{a \times b}{\text{GCD}(a,b)}

A Python implementation is:

def gcd(a, b):
    while b:
        a, b = b, a % b
    return abs(a)

def lcm(a, b):
    if a == 0 or b == 0:
        return 0

    return abs((a // gcd(a, b)) * b)

print("GCD:", gcd(12, 18))
print("LCM:", lcm(12, 18))

Output:

GCD: 6
LCM: 36

Python also provides math.gcd() and, in modern Python versions, math.lcm().

18. Checking Palindromes

A palindrome is a word, number, or sequence that reads the same forward and backward.

Examples:

  • madam

  • level

  • 121

  • 1331

Python Program

text = "madam"

if text == text[::-1]:
    print("Palindrome")
else:
    print("Not a palindrome")

Output:

Palindrome

The expression text[::-1] creates a reversed copy of the string.

Palindrome Function

def is_palindrome(text):
    text = text.lower()
    return text == text[::-1]

print(is_palindrome("Madam"))
print(is_palindrome("Python"))

Output:

True
False

This version ignores letter case but not spaces or punctuation.

Challenge: Ignore Spaces and Punctuation

Can you modify the function so that a phrase such as "A man, a plan, a canal: Panama" is recognized as a palindrome?

Hint: Keep only alphanumeric characters using str.isalnum() before comparing the text with its reverse.

19. Checking Anagrams

Two words are anagrams if they contain exactly the same letters with the same frequencies, but in a different order.

Examples:

  • listen and silent

  • earth and heart

  • race and care

Python Program

def are_anagrams(word1, word2):
    word1 = word1.replace(" ", "").lower()
    word2 = word2.replace(" ", "").lower()

    return sorted(word1) == sorted(word2)

print(are_anagrams("listen", "silent"))
print(are_anagrams("hello", "world"))

Output:

True
False

The program:

  1. Converts both words to lowercase.

  2. Removes spaces.

  3. Sorts the characters in each word.

  4. Compares the sorted results.

Anagram Detection Using Frequency Counting

from collections import Counter

def are_anagrams(word1, word2):
    word1 = word1.replace(" ", "").lower()
    word2 = word2.replace(" ", "").lower()

    return Counter(word1) == Counter(word2)

print(are_anagrams("earth", "heart"))

Output:

True

Frequency counting avoids sorting and is often a convenient way to compare character counts.


Part 4: Understanding Algorithm Efficiency

A program can produce the correct answer and still be inefficient when given a large amount of data.

Time complexity describes how the work performed by an algorithm grows as the input size increases.

Here is a beginner-friendly reference table.

ComplexityCommon exampleGeneral interpretation
O(1)O(1)Access a list element by indexConstant-time operation
O(log⁡n)O(\log n)Binary SearchGrows slowly
O(n)O(n)Linear SearchWork grows roughly with input size
O(nlog⁡n)O(n\log n)Efficient general-purpose sortingScales well for many large lists
O(n2)O(n^2)Basic Bubble SortCan become slow as input grows

These are typical complexity descriptions; actual performance also depends on the data, implementation, and execution environment.

Why does it matter?

Suppose you have one million sorted numbers.

  • Linear Search may need to inspect up to one million elements.

  • Binary Search needs roughly 20 comparisons in the worst case for a list of that size.

That is why choosing the right algorithm matters.


Part 5: Mini-Projects for Practice

Project 1: Student Marks Analyzer

Goal: Analyze the marks of students in a class.

Your program should:

  1. Store marks in a list.

  2. Calculate the maximum and minimum marks.

  3. Calculate the total and average.

  4. Sort the marks in descending order.

  5. Count how many students scored above 75.

  6. Search for a particular mark.

Starter code:

marks = [78, 92, 65, 88, 92, 71, 56, 85]

print("Highest:", max(marks))
print("Lowest:", min(marks))
print("Average:", sum(marks) / len(marks))

print("Descending order:", sorted(marks, reverse=True))

above_75 = 0

for mark in marks:
    if mark > 75:
        above_75 += 1

print("Students scoring above 75:", above_75)

Expected output:

Highest: 92
Lowest: 56
Average: 78.375
Descending order: [92, 92, 88, 85, 78, 71, 65, 56]
Students scoring above 75: 5

Extension: Ask the user to enter a mark and use Binary Search to find it in a sorted list.

Project 2: Number Toolkit

Create a menu-driven program that allows a user to:

  1. Check whether a number is prime.

  2. Calculate factorial.

  3. Generate Fibonacci numbers.

  4. Check whether a number is a palindrome.

  5. Find the GCD and LCM of two numbers.

Extension: Validate the user's input and allow the program to continue until the user selects Exit.

Project 3: Word Analyzer

Write a program that accepts a sentence and:

  • Counts the frequency of each word.

  • Identifies repeated words.

  • Finds the longest word.

  • Checks whether two entered words are anagrams.

  • Checks whether the sentence is a palindrome after ignoring spaces and punctuation.

Extension: Display the five most frequently used words.


Part 6: Practice Questions

Try these questions before looking for solutions.

A. Conceptual Questions

  1. What is an algorithm? Give one real-life example.

  2. Why must the input list be sorted before applying Binary Search?

  3. What is the main difference between Bubble Sort and Selection Sort?

  4. What is the difference between list.sort() and sorted(list)?

  5. What does O(n)O(n) mean?

  6. Why does Binary Search generally outperform Linear Search on large, sorted lists?

  7. What is the purpose of the key parameter in Python's sorting functions?

  8. Why is a set useful for detecting duplicates?

B. Programming Challenges

  1. Write a Linear Search function that returns the index of the first occurrence of a target.

  2. Implement Binary Search and test it with both present and absent values.

  3. Write Bubble Sort to arrange a list in descending order.

  4. Implement Selection Sort without using sort() or sorted().

  5. Write Insertion Sort and count how many shifts are performed.

  6. Sort a list of names alphabetically using sorted().

  7. Sort student records by marks in descending order and use names alphabetically to break ties.

  8. Find the second-largest distinct number in a list.

  9. Count the frequency of each character in a string.

  10. Identify all duplicate values in a list.

  11. Print all prime numbers between 1 and 100.

  12. Generate the first n Fibonacci numbers.

  13. Calculate factorial using iteration.

  14. Find the GCD and LCM of two numbers.

  15. Check whether a phrase is a palindrome after ignoring case, spaces, and punctuation.

  16. Check whether two phrases are anagrams after ignoring case and spaces.

  17. Build a menu-driven program that combines at least five of the algorithms in this article.


Quick Revision: Algorithms Cheat Sheet

ProblemUseful approach
Search an unsorted listLinear Search
Search a sorted listBinary Search
Sort a list in Pythonsort() or sorted()
Learn basic sorting logicBubble, Selection, Insertion Sort
Find maximum/minimummax() / min() or a loop
Calculate totalsum() or accumulation
Count repeated valuesDictionary or Counter
Detect duplicatesSet
Test a prime numberDivisibility checks up to the square root
Generate Fibonacci numbersIterative updates
Calculate factorialMultiplication loop
Find GCDEuclid's algorithm
Find LCMUse GCD
Check palindromeCompare with reversed text
Check anagramCompare sorted characters or frequencies

Final Thoughts

Algorithms are the foundation of problem-solving in programming. Once you understand how searching, sorting, counting, and number-based algorithms work, you will be better prepared to solve school programming questions, build useful projects, and explore more advanced topics such as data structures, competitive programming, and artificial intelligence.

Remember: Do not just memorize the code. Understand the steps, test different inputs, and try to improve your solution.

Your next Python Pebble challenge: Pick one algorithm from this tutorial, write it without looking at the example, test it on at least three inputs, and explain its logic in your own words.

Keep coding, keep experimenting, and keep collecting Python Pebbles!


Python Data Structures - Collections

 

Python Data Structures Beyond Basic Collections: Stack, Queue, Deque, Linked List, Searching and Sorting

Have you ever wondered how a browser remembers the pages you visited, how a printer manages multiple print requests, or how a shopping app sorts products by price?

These activities use ideas from data structures and algorithms.

In Python, you already know basic collections such as lists, tuples, sets, and dictionaries. But as programs become more advanced, you need to understand how to organize, access, search, and arrange data efficiently.

Welcome to this Python Pebbles tutorial, where we will explore six important topics for Class 9–12 students:

  • Stack

  • Queue

  • Deque

  • Linked list

  • Searching algorithms

  • Sorting algorithms

By the end, you will build a small Student Record Manager that uses searching and sorting.


1. What Is a Data Structure?

A data structure is a way of organizing and storing data so that a program can use it effectively.

Imagine your school library.

Books are not thrown randomly onto the floor. They are organized so that students and librarians can find them easily.

A computer program also needs a sensible way to organize information.

Examples:

Data StructureReal-Life Example
StackA pile of plates
QueueStudents waiting in a line
DequeA line where people can join or leave at either end
Linked listA chain of connected links
SearchingFinding a student's roll number
SortingArranging marks from lowest to highest

Python Pebble: Choosing the right way to organize data can make a program easier to understand and more efficient.

2. Stack – Last In, First Out (LIFO)

What is a Stack?

A stack is a data structure in which the last item added is the first item removed.

This rule is called LIFO — Last In, First Out.

Imagine placing three plates on top of one another.

       ┌───────────┐
       │  Plate C  │  ← Removed first
       ├───────────┤
       │  Plate B  │
       ├───────────┤
       │  Plate A  │
       └───────────┘

You normally remove Plate C first because it is on top.

Stacks are used in:

  • Undo operations in text editors

  • Browser history navigation

  • Function calls

  • Expression evaluation

  • Backtracking problems

Stack Operations

OperationMeaning
pushAdd an item
popRemove the top item
peekView the top item without removing it
is_emptyCheck whether the stack is empty

Python lists can implement a simple stack.

Example 1: Creating a Stack

stack = []

stack.append("Book A")
stack.append("Book B")
stack.append("Book C")

print(stack)

Output:

['Book A', 'Book B', 'Book C']

Here, append() adds an item to the top of our stack.

Example 2: Removing an Item

stack = ["Book A", "Book B", "Book C"]

removed = stack.pop()

print("Removed:", removed)
print("Stack:", stack)

Output:

Removed: Book C
Stack: ['Book A', 'Book B']

The last item added is the first item removed.

Example 3: Complete Stack Program

stack = []

stack.append(10)
stack.append(20)
stack.append(30)

print("Stack:", stack)
print("Top item:", stack[-1])

removed = stack.pop()

print("Removed:", removed)
print("Updated stack:", stack)

Output:

Stack: [10, 20, 30]
Top item: 30
Removed: 30
Updated stack: [10, 20]

Notice that stack[-1] accesses the last element without removing it.

Mini Challenge 1

Create a stack of five subject names.

  1. Add five subjects.

  2. Display the stack.

  3. Remove two subjects.

  4. Display the updated stack.

Bonus: Print the last subject without removing it.


3. Queue – First In, First Out (FIFO)

What Is a Queue?

A queue is a data structure in which the first item added is the first item removed.

This rule is called FIFO — First In, First Out.

Imagine students waiting at a school canteen.

Front                         Rear
  ↓                             ↓
[Riya] → [Aman] → [Neha] → [Raman]
  ↑
Served first

Riya joined the line first, so she is served first.

Queues are used in:

  • Printer job management

  • Customer service systems

  • Task scheduling

  • Network message processing

  • Breadth-first search in graphs

Queue Operations

OperationMeaning
enqueueAdd an item at the rear
dequeueRemove an item from the front
frontView the first item
is_emptyCheck whether the queue is empty

Example 1: A Simple Queue

A Python list can demonstrate a queue for small examples.

queue = []

queue.append("Riya")
queue.append("Aman")
queue.append("Neha")

print(queue)

Output:

['Riya', 'Aman', 'Neha']

To remove the first item:

served = queue.pop(0)

print("Served:", served)
print("Waiting:", queue)

Output:

Served: Riya
Waiting: ['Aman', 'Neha']

This works, but removing the first item from a large list can be inefficient because the remaining items need to shift.

Example 2: The Recommended Queue Using deque

Python provides a double-ended queue in the collections module.

from collections import deque

queue = deque()

queue.append("Riya")
queue.append("Aman")
queue.append("Neha")

print(queue)

served = queue.popleft()

print("Served:", served)
print("Waiting:", queue)

Output:

deque(['Riya', 'Aman', 'Neha'])
Served: Riya
Waiting: deque(['Aman', 'Neha'])

popleft() efficiently removes an item from the front.

Mini Challenge 2

Create a queue for a school office.

  • Add three student names.

  • Remove the first student after their work is completed.

  • Add one more student.

  • Display the queue.

Question: Why should the first student be removed rather than the last student?


4. Deque – Insert and Remove at Both Ends

What Is a Deque?

A deque, pronounced “deck,” stands for double-ended queue.

Unlike a standard queue, a deque allows items to be added or removed at both ends.

Imagine a line where people are allowed to enter or leave from either the front or the rear.

Python provides deque through the collections module.

from collections import deque

Important Deque Operations

OperationMeaning
append(x)Add x at the right end
appendleft(x)Add x at the left end
pop()Remove from the right end
popleft()Remove from the left end

Example 1: Adding Items at Both Ends

from collections import deque

numbers = deque([20, 30])

numbers.append(40)
numbers.appendleft(10)

print(numbers)

Output:

deque([10, 20, 30, 40])

Example 2: Removing Items at Both Ends

from collections import deque

numbers = deque([10, 20, 30, 40])

print(numbers.pop())
print(numbers.popleft())

print(numbers)

Output:

40
10
deque([20, 30])

Where Are Deques Useful?

Deques are useful when a program needs to add and remove items at either end.

Examples include:

  • Sliding-window algorithms

  • Recent-item history

  • Palindrome checking

  • Certain scheduling algorithms

  • Implementing stacks and queues

Mini Challenge 3: Palindrome Checker

A palindrome reads the same forwards and backwards.

Examples:

LEVEL
MADAM
RADAR

Try writing a program that:

  1. Takes a word from the user.

  2. Places its characters into a deque.

  3. Compares and removes characters from both ends.

  4. Reports whether the word is a palindrome.

Hint: Compare popleft() with pop() until zero or one character remains.


5. Linked List – An Introduction

What Is a Linked List?

A linked list is a data structure made of nodes.

Each node stores:

  1. Data

  2. A reference to the next node

Unlike a Python list, whose elements are stored in a sequence managed by Python, a linked list connects its nodes through references.

Imagine a treasure hunt.

Each clue contains a message and tells you where to find the next clue.

[10 | next] → [20 | next] → [30 | None]

Each box represents a node.

The final node points to None, which indicates that there is no next node.

Creating a Node in Python

We can use a class to define a node.

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

Here:

  • data stores the value.

  • next stores a reference to the next node.

  • None means there is no next node yet.

Example 1: Connecting Three Nodes

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None


first = Node(10)
second = Node(20)
third = Node(30)

first.next = second
second.next = third

print(first.data)
print(first.next.data)
print(first.next.next.data)

Output:

10
20
30

We have created three nodes and connected them.

Example 2: Traversing a Linked List

Traversing means visiting each node one by one.

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None


first = Node(10)
second = Node(20)
third = Node(30)

first.next = second
second.next = third

current = first

while current is not None:
    print(current.data)
    current = current.next

Output:

10
20
30

The variable current moves from one node to the next until it reaches None.

A Simple Linked List Class

Let's make our code reusable.

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None


class LinkedList:
    def __init__(self):
        self.head = None

    def append(self, data):
        new_node = Node(data)

        if self.head is None:
            self.head = new_node
            return

        current = self.head

        while current.next is not None:
            current = current.next

        current.next = new_node

    def display(self):
        current = self.head

        while current is not None:
            print(current.data, end=" -> ")
            current = current.next

        print("None")


numbers = LinkedList()

numbers.append(10)
numbers.append(20)
numbers.append(30)

numbers.display()

Output:

10 -> 20 -> 30 -> None

Linked List vs Python List

FeaturePython ListSingly Linked List
Access by indexFast, typically O(1)Requires traversal, O(n)
Add at beginningTypically O(n)O(1) if the head is updated
Add at endUsually amortized O(1) with append()O(n) in our implementation without a tail reference
Memory layoutManaged sequence of referencesNodes connected by references
Built into PythonYesUsually implemented manually for learning

Python Pebble: Linked lists are excellent for learning how nodes and references work. For everyday Python programming, built-in lists are often the simpler choice.

Mini Challenge 4

Extend the linked list program to:

  1. Add the numbers 5, 15, 25, and 35.

  2. Display all nodes.

  3. Count how many nodes exist.

Bonus: Write a method that searches for a particular value.


6. Searching Algorithms

What Is Searching?

Searching means finding whether a particular item exists in a collection and, if needed, identifying its position.

Imagine looking for your name in a class register.

A computer can use different searching algorithms depending on how the data is organized.

We will learn:

  • Linear search

  • Binary search

6.1 Linear Search

Linear search checks each element one by one until the target is found or the collection ends.

It works on both sorted and unsorted collections.

Example

numbers = [15, 8, 23, 42, 16]

target = 42
found = False

for i in range(len(numbers)):
    if numbers[i] == target:
        print("Found at index:", i)
        found = True
        break

if not found:
    print("Not found")

Output:

Found at index: 3

Remember that Python indexes start at zero.

The first element is at index 0, the second at index 1, and so on.

Linear Search as a Function

def linear_search(items, target):
    for index, item in enumerate(items):
        if item == target:
            return index

    return -1


numbers = [15, 8, 23, 42, 16]

print(linear_search(numbers, 42))
print(linear_search(numbers, 100))

Output:

3
-1

Here, -1 means that the target was not found.

Time Complexity

In the worst case, linear search may inspect every element.

Its time complexity is O(n), where n is the number of elements.


6.2 Binary Search

Binary search is a faster searching method, but there is one important condition:

The data must be sorted.

Imagine finding a word in a dictionary. Instead of reading every word, you open near the middle and decide which half to search.

Binary search follows the same idea.

Example

Sorted list:

[10, 20, 30, 40, 50, 60, 70]

Suppose we want to find 60.

  1. Check the middle element: 40.

  2. Since 60 is greater than 40, ignore the left half.

  3. Check the middle of the remaining section: 60.

  4. The target is found.

Python Program

def binary_search(items, target):
    low = 0
    high = len(items) - 1

    while low <= high:
        mid = (low + high) // 2

        if items[mid] == target:
            return mid

        elif items[mid] < target:
            low = mid + 1

        else:
            high = mid - 1

    return -1


numbers = [10, 20, 30, 40, 50, 60, 70]

print(binary_search(numbers, 60))
print(binary_search(numbers, 25))

Output:

5
-1

Time Complexity

Binary search halves the remaining search area at each step.

Its time complexity is O(log n).

For large sorted collections, this can be much faster than linear search.

Linear Search vs Binary Search

FeatureLinear SearchBinary Search
Requires sorted dataNoYes
MethodCheck items one by oneRepeatedly halve the search range
Worst-case timeO(n)O(log n)
Best forSmall or unsorted dataLarge, sorted data

Mini Challenge 5

Write a program that searches for a student's roll number in this list:

roll_numbers = [101, 105, 108, 112, 120, 125, 130]

First use linear search.

Then use binary search.

Question: Why must the list be sorted before using binary search?


7. Sorting Algorithms

What Is Sorting?

Sorting means arranging data in a particular order.

Examples:

  • Marks from lowest to highest

  • Prices from lowest to highest

  • Names in alphabetical order

  • Scores from highest to lowest

Python provides built-in sorting tools, but understanding sorting algorithms helps you learn how they work.

We will explore:

  • Bubble sort

  • Selection sort

  • Insertion sort

  • Python's built-in sorting

7.1 Bubble Sort

Bubble sort repeatedly compares adjacent elements and swaps them when they are in the wrong order.

Think of larger values gradually moving towards the end of the list.

Example

Original list:

[5, 3, 8, 2]

First pass:

  • Compare 5 and 3: swap.

  • Compare 5 and 8: no swap.

  • Compare 8 and 2: swap.

The list becomes:

[3, 5, 2, 8]

After further passes, the list becomes:

[2, 3, 5, 8]

Python Program

def bubble_sort(numbers):
    numbers = numbers.copy()
    n = len(numbers)

    for i in range(n):
        swapped = False

        for j in range(0, n - i - 1):
            if numbers[j] > numbers[j + 1]:
                numbers[j], numbers[j + 1] = (
                    numbers[j + 1], numbers[j]
                )
                swapped = True

        if not swapped:
            break

    return numbers


data = [5, 3, 8, 2]

print(bubble_sort(data))

Output:

[2, 3, 5, 8]

Bubble sort has worst-case time complexity O(n²).

It is useful for learning, but it is generally not the best choice for sorting large datasets.


7.2 Selection Sort

Selection sort repeatedly finds the smallest remaining element and places it in the next position.

Example

Original list:

[29, 10, 14, 37, 13]

Steps:

  1. Find the smallest value, 10, and place it first.

  2. Find the smallest value among the remaining elements, 13.

  3. Continue until the list is sorted.

Result:

[10, 13, 14, 29, 37]

Python Program

def selection_sort(numbers):
    numbers = numbers.copy()
    n = len(numbers)

    for i in range(n):
        min_index = i

        for j in range(i + 1, n):
            if numbers[j] < numbers[min_index]:
                min_index = j

        numbers[i], numbers[min_index] = (
            numbers[min_index], numbers[i]
        )

    return numbers


data = [29, 10, 14, 37, 13]

print(selection_sort(data))

Output:

[10, 13, 14, 29, 37]

Selection sort has worst-case time complexity O(n²).


7.3 Insertion Sort

Insertion sort builds a sorted section one element at a time.

Imagine arranging playing cards in your hand. You pick up a card and insert it into the correct position among the cards already arranged.

Example

Original list:

[5, 2, 4, 1]

The list is gradually arranged until it becomes:

[1, 2, 4, 5]

Python Program

def insertion_sort(numbers):
    numbers = numbers.copy()

    for i in range(1, len(numbers)):
        key = numbers[i]
        j = i - 1

        while j >= 0 and numbers[j] > key:
            numbers[j + 1] = numbers[j]
            j -= 1

        numbers[j + 1] = key

    return numbers


data = [5, 2, 4, 1]

print(insertion_sort(data))

Output:

[1, 2, 4, 5]

Insertion sort has worst-case time complexity O(n²). It can perform well on small or nearly sorted lists.


7.4 Python's Built-in Sorting

In real projects, Python's built-in sorting is usually the best starting point.

Using sort()

marks = [78, 92, 65, 88, 73]

marks.sort()

print(marks)

Output:

[65, 73, 78, 88, 92]

sort() changes the original list.

Using sorted()

marks = [78, 92, 65, 88, 73]

result = sorted(marks)

print("Original:", marks)
print("Sorted:", result)

Output:

Original: [78, 92, 65, 88, 73]
Sorted: [65, 73, 78, 88, 92]

sorted() returns a new sorted list.

Sorting in Descending Order

marks = [78, 92, 65, 88, 73]

print(sorted(marks, reverse=True))

Output:

[92, 88, 78, 73, 65]

Sorting Names Alphabetically

students = ["Riya", "Aman", "Neha", "Raman"]

print(sorted(students))

Output:

['Aman', 'Neha', 'Raman', 'Riya']

Python Pebble: Learn how algorithms work, but use Python's built-in sorting for most everyday applications.

Sorting Algorithm Comparison

AlgorithmAverage/Worst-Case TimeMain Idea
Bubble sortO(n²)Compare adjacent elements
Selection sortO(n²)Select the smallest remaining element
Insertion sortO(n²)Insert into the sorted section
Python's built-in sortO(n log n) worst caseEfficient, adaptive sorting

8. Searching and Sorting Together

Searching and sorting are often used together.

Imagine a teacher has marks for 10 students.

The teacher wants to:

  1. Arrange the marks from lowest to highest.

  2. Find whether a student scored 85.

  3. Display the position of that score in the sorted list.

Complete Example

marks = [72, 85, 63, 91, 78, 85]

sorted_marks = sorted(marks)

print("Sorted marks:", sorted_marks)

target = 85

index = sorted_marks.index(target)

print("First occurrence of 85 is at index:", index)

Output:

Sorted marks: [63, 72, 78, 85, 85, 91]
First occurrence of 85 is at index: 3

Remember: .index() returns the first occurrence, and indexes start at zero.

If you use binary search instead, remember to provide sorted data.


9. Master Project – Student Record Manager

Now let's combine searching and sorting in a practical program.

Project Requirements

Create a program that:

  1. Stores student names and marks.

  2. Displays all students.

  3. Sorts students by marks.

  4. Searches for a student by name.

  5. Displays the highest-scoring student.

Python Program

students = [
    {"name": "Riya", "marks": 88},
    {"name": "Aman", "marks": 76},
    {"name": "Neha", "marks": 95},
    {"name": "Raman", "marks": 82},
    {"name": "Arjun", "marks": 91}
]


def display_students(records):
    for student in records:
        print(student["name"], "-", student["marks"])


def sort_by_marks(records):
    return sorted(
        records,
        key=lambda student: student["marks"]
    )


def search_student(records, name):
    for student in records:
        if student["name"].lower() == name.lower():
            return student

    return None


print("All Students:")
display_students(students)

print("\nSorted by Marks:")
display_students(sort_by_marks(students))

name = input("\nEnter student name to search: ")
result = search_student(students, name)

if result is not None:
    print("Found:", result["name"], result["marks"])
else:
    print("Student not found")

topper = max(students, key=lambda student: student["marks"])

print("\nTopper:", topper["name"], topper["marks"])

Example output for a search for Neha:

All Students:
Riya - 88
Aman - 76
Neha - 95
Raman - 82
Arjun - 91

Sorted by Marks:
Aman - 76
Raman - 82
Riya - 88
Arjun - 91
Neha - 95

Enter student name to search: Neha
Found: Neha 95

Topper: Neha 95

Master Challenge

Extend the project by adding:

  • A menu-driven interface.

  • A stack to store the last few operations.

  • A queue for students waiting to be processed.

  • A deque to maintain a recent-history list.

  • A linked list to store student records for practice.

  • Linear and binary search options.

  • Sorting by name or marks.

  • Input validation for marks between 0 and 100.

For a more realistic application, you can keep student records in a list of dictionaries. Use a linked list as a separate exercise to understand node-based data structures.


10. Practice Questions

Level 1 – Concepts

  1. What is a data structure?

  2. What does LIFO stand for?

  3. What does FIFO stand for?

  4. Which data structure allows insertion and removal at both ends?

  5. What information does a node in a singly linked list contain?

  6. What is the difference between linear and binary search?

  7. Why must data be sorted before binary search?

  8. What is the purpose of sorting?

  9. What does pop() do when used on a list as a stack?

  10. What is the difference between sort() and sorted()?

Level 2 – Coding

  1. Write a stack program that pushes five integers and pops two.

  2. Create a queue using collections.deque.

  3. Create a deque and add an item to each end.

  4. Create three linked-list nodes and connect them.

  5. Write a function for linear search.

  6. Write a function for binary search on sorted data.

  7. Implement bubble sort.

  8. Implement selection sort.

  9. Implement insertion sort.

  10. Sort student records by marks using sorted().

Level 3 – Thinking Challenges

  1. Which data structure would you choose for an undo feature? Explain why.

  2. Which data structure would you use for a printer queue?

  3. Why can binary search be faster than linear search?

  4. Why is a linked list not as convenient as a Python list for accessing the element at index 100?

  5. Which sorting algorithm would you choose for a small, nearly sorted list, and why?

  6. How could a deque help check whether a word is a palindrome?

  7. What happens when you pop from an empty list?

  8. How would you avoid searching a student record list repeatedly?

  9. How would you modify the Student Record Manager to sort marks in descending order?

  10. Why should an algorithm's time complexity matter when working with thousands of records?


11. Quick Revision Table

TopicKey IdeaPython Tool
StackLast In, First Outlist.append(), list.pop()
QueueFirst In, First Outcollections.deque
DequeOperations at both endsappendleft(), popleft()
Linked listNodes connected by referencesClasses and references
Linear searchCheck items one by oneLoop
Binary searchRepeatedly halve sorted search rangeLoop and indexes
Bubble sortCompare adjacent elementsNested loops
Selection sortSelect the smallest remaining itemNested loops
Insertion sortInsert into sorted sectionLoop
Built-in sortingEfficient general-purpose sortingsort(), sorted()

12. Python Pebble

A good programmer knows how to store data. A great programmer also understands how to access, search, and organize it efficiently.

Stacks help manage the latest item first. Queues process items in arrival order. Deques work at both ends. Linked lists teach you how nodes connect. Searching finds information, and sorting organizes it.

Start with small examples, trace each step by hand, and then write your own programs.

Your next step: Complete the Student Record Manager, test it with different data, and experiment with the time complexity of your searching and sorting algorithms.

Thursday, October 8, 2026

Python Modules and Packages

 

Python Modules and Packages – Organize Your Python Programs Like a Pro

When Python programs become bigger, putting everything into one file can make the code difficult to understand, maintain, and reuse.

Imagine you have a school bag containing books for Maths, Science, English, and Computer Science. Would you put everything into one notebook?

Probably not!

You would keep different subjects in different notebooks and organize them properly.

Python provides Modules and Packages to do exactly the same thing with programs.

In this Python Pebbles tutorial, we will learn:

  • What is a module?

  • How import works

  • from ... import

  • Built-in modules

  • The math module

  • The random module

  • The datetime module

  • The os module

  • The statistics module

  • How to create your own module

  • What are packages?

  • How to install packages using pip

  • Practice questions

  • Mini challenges

  • A master project


1. What is a Module?

A module is simply a Python file containing Python code.

A module can contain:

  • Variables

  • Functions

  • Classes

  • Statements

A Python module normally has the extension:

.py

For example:

calculator.py

can contain:

def add(a, b):
    return a + b

def subtract(a, b):
    return a - b

Now another Python program can use these functions instead of writing them again.

Think of a module as a toolbox

Imagine you have a toolbox containing:

hammer
screwdriver
spanner
pliers

Instead of carrying every tool separately, you carry the toolbox.

Similarly, a Python module can contain a collection of useful functions.

calculator.py
       |
       +-- add()
       +-- subtract()
       +-- multiply()
       +-- divide()

Other Python programs can use these functions.


2. Why Do We Need Modules?

Modules provide several advantages.

1. Code Reusability

Write a function once and use it in multiple programs.

2. Better Organization

Large programs can be divided into smaller files.

3. Easier Maintenance

If something needs to be changed, you can modify the appropriate module.

4. Avoid Repeating Code

You don't need to write the same functions again and again.

5. Collaboration

Different programmers can work on different modules.


3. The import Statement

Python provides the import statement to use a module.

For example:

import math

Now we can use functions available inside the math module.

import math

print(math.sqrt(25))

Output:

5.0

Notice the syntax:

module_name.function_name()

Here:

math.sqrt()

means:

Use the sqrt() function from the math module.


4. Importing More Than One Module

We can import multiple modules.

import math
import random
import statistics

Now all three modules are available to our program.


5. Importing a Module with an Alias

Sometimes a module name can be long.

We can give it another name using as.

import statistics as stats

Now we can write:

print(stats.mean([10, 20, 30]))

Output:

20

The general syntax is:

import module_name as short_name

For example:

import math as m

print(m.sqrt(81))

Output:

9.0

6. from ... import

Sometimes we don't want to import the entire module.

We can import a particular function.

For example:

from math import sqrt

Now we can directly use:

print(sqrt(49))

Output:

7.0

Notice that we don't need:

math.sqrt()

We can simply write:

sqrt()

7. Importing Multiple Functions

We can import multiple functions.

from math import sqrt, factorial, ceil

Example:

print(sqrt(64))
print(factorial(5))
print(ceil(4.2))

Output:

8.0
120
5

8. import vs from ... import

Let's compare.

Using import

import math

print(math.sqrt(100))

Using from ... import

from math import sqrt

print(sqrt(100))

Both produce:

10.0

Python Pebble

Using:

import math

makes it very clear where sqrt() came from:

math.sqrt()

This can make larger programs easier to understand.


9. Built-in Modules

Python comes with a large collection of modules.

These are often called standard library modules.

You don't normally need to install them separately.

Some useful modules are:

ModuleCommon Use
mathMathematical operations
randomRandom numbers and choices
datetimeDates and time
osOperating-system operations
statisticsStatistical calculations

Let's explore them one by one.


10. The math Module

The math module provides many mathematical functions and constants.

First:

import math

Square Root

print(math.sqrt(81))

Output:

9.0

Power

print(math.pow(2, 5))

Output:

32.0

Factorial

print(math.factorial(5))

Output:

120

Because:

5! = 5 × 4 × 3 × 2 × 1

Ceiling

ceil() rounds a number upward.

print(math.ceil(4.2))

Output:

5

Floor

floor() rounds a number downward.

print(math.floor(4.9))

Output:

4

Mathematical Constants

Python provides useful constants.

print(math.pi)

Output will be approximately:

3.141592653589793

Example:

radius = 5

area = math.pi * radius * radius

print("Area =", area)

11. The random Module

Computers normally generate pseudo-random values.

Python provides the random module for generating random values.

Start with:

import random

Generate a Random Number

print(random.randint(1, 10))

Possible output:

7

Another run could produce:

3

The result can change each time.


Random Number Between Two Values

number = random.randint(100, 999)

print(number)

This generates a random integer between 100 and 999, inclusive.


Random Choice

Suppose we have:

colors = ["Red", "Green", "Blue", "Yellow"]

We can randomly select one:

print(random.choice(colors))

Possible output:

Blue

Randomly Select a Student

students = ["Raman", "Aman", "Riya", "Neha"]

winner = random.choice(students)

print("Winner:", winner)

Possible output:

Winner: Riya

Shuffle a List

numbers = [1, 2, 3, 4, 5]

random.shuffle(numbers)

print(numbers)

Possible output:

[3, 1, 5, 2, 4]

The order may be different every time.

Mini Challenge

Create a program that randomly selects one number from:

1 to 100

and prints:

Lucky Number: <number>

12. The datetime Module

The datetime module is used for working with:

  • Dates

  • Times

  • Date and time calculations

Import it:

import datetime

Get Current Date and Time

now = datetime.datetime.now()

print(now)

Possible output:

2026-10-08 15:30:25.123456

The exact result depends on when the program is executed.


Get Today's Date

today = datetime.date.today()

print(today)

Possible output:

2026-10-08

Extract Year, Month and Day

today = datetime.date.today()

print("Year:", today.year)
print("Month:", today.month)
print("Day:", today.day)

Create a Specific Date

birthday = datetime.date(2012, 8, 15)

print(birthday)

Output:

2012-08-15

Calculate Difference Between Dates

today = datetime.date.today()
exam_date = datetime.date(2026, 12, 1)

remaining = exam_date - today

print("Days remaining:", remaining.days)

This is useful for creating:

  • Exam countdowns

  • Birthday reminders

  • Project deadlines

  • Event countdowns

Python Pebble

Dates can be subtracted to calculate the difference between them.


13. The os Module

The os module allows Python to interact with the operating system.

Import it:

import os

It can be used for tasks such as:

  • Working with folders

  • Checking files

  • Getting the current directory

  • Creating directories

  • Listing directory contents


Current Working Directory

print(os.getcwd())

getcwd() means:

Get Current Working Directory

Possible output:

C:\Users\Student\PythonProjects

List Files and Folders

print(os.listdir())

Possible output:

['program.py', 'data.txt', 'images', 'projects']

Create a Folder

os.mkdir("PythonProjects")

This creates a folder named:

PythonProjects

Be careful: if the folder already exists, Python will raise an error.


Check Whether a File Exists

import os

if os.path.exists("data.txt"):
    print("File exists")
else:
    print("File does not exist")

This is extremely useful in real-world programs.


14. The statistics Module

The statistics module provides common statistical functions.

Import it:

import statistics

Mean

The mean is the average.

marks = [70, 80, 90, 60, 100]

print(statistics.mean(marks))

Output:

80

Median

numbers = [10, 20, 30, 40, 50]

print(statistics.median(numbers))

Output:

30

Mode

Mode is the value that occurs most frequently.

numbers = [10, 20, 20, 30, 20, 40]

print(statistics.mode(numbers))

Output:

20

Complete Example

import statistics

marks = [78, 85, 92, 67, 88]

print("Mean:", statistics.mean(marks))
print("Median:", statistics.median(marks))
print("Mode:", statistics.mode(marks))

15. Creating Your Own Module

One of the most useful features of Python is that you can create your own modules.

Suppose we create a file:

calculator.py

Add:

def add(a, b):
    return a + b


def subtract(a, b):
    return a - b


def multiply(a, b):
    return a * b


def divide(a, b):
    return a / b

Now create another file:

main.py

We can import our module:

import calculator

Then:

print(calculator.add(10, 5))
print(calculator.subtract(10, 5))
print(calculator.multiply(10, 5))
print(calculator.divide(10, 5))

Output:

15
5
50
2.0

16. Understanding the Folder Structure

Our project may look like this:

MyProject/
│
├── main.py
└── calculator.py

calculator.py is our module.

main.py is the program that uses it.

This is the beginning of writing well-organized Python programs.


17. Importing Specific Functions from Your Module

Instead of:

import calculator

print(calculator.add(10, 20))

we can write:

from calculator import add

print(add(10, 20))

Output:

30

We can also import multiple functions:

from calculator import add, multiply

print(add(5, 10))
print(multiply(5, 10))

18. The __name__ Check

You may see this statement in Python modules:

if __name__ == "__main__":

For example:

def add(a, b):
    return a + b


if __name__ == "__main__":
    print(add(10, 20))

This allows us to run some code only when the file is executed directly.

It will not run that section when the module is imported by another program.

Python Pebble

Think of it as:

"Run this part only when I am the main program."

This becomes especially useful when creating reusable modules.


19. What is a Package?

A package is a way of organizing multiple Python modules.

Think about the difference:

Module
   ↓
One Python file

while:

Package
   ↓
Folder
   ├── module1.py
   ├── module2.py
   └── module3.py

A package helps organize larger projects.


20. Example of a Package

Suppose we create:

school/
│
├── maths.py
├── science.py
└── english.py

The folder school can be used to organize modules related to school subjects.

For example:

maths.py

def square(n):
    return n * n

science.py

def gravity():
    return 9.8

We can import them using:

from school import maths

print(maths.square(5))

Output:

25

Or:

from school.maths import square

print(square(8))

Output:

64

21. Package Structure

A larger project could look like:

MyProject/
│
├── main.py
│
└── school/
    ├── __init__.py
    ├── maths.py
    ├── science.py
    └── english.py

The __init__.py file has traditionally been used to identify a directory as a Python package.

Modern Python also supports namespace packages, so __init__.py is not always required. For beginners, however, it is useful to understand it as part of the traditional package structure.


22. Installing Packages with pip

Python has a huge ecosystem of third-party packages.

Examples include packages for:

  • Data analysis

  • Machine learning

  • Web development

  • Automation

  • Visualization

  • Artificial intelligence

  • Scientific computing

One of the most common tools used to install Python packages is:

pip

23. What is pip?

pip is Python's package installer.

It allows us to install packages from the Python Package Index, commonly known as PyPI.

For example:

pip install requests

This installs the requests package.

Then we can use it in Python:

import requests

24. Installing Popular Python Packages

For example:

pip install numpy
pip install pandas
pip install matplotlib
pip install yfinance

These packages are commonly used in data analysis, visualization, finance and other Python applications.


25. Checking Installed Packages

You can use:

pip list

This displays packages installed in your Python environment.

You can also check a particular package:

pip show numpy

26. Upgrading a Package

To upgrade a package:

pip install --upgrade numpy

27. Uninstalling a Package

To remove a package:

pip uninstall numpy

Python will normally ask for confirmation before uninstalling it.


28. Installing Packages in Google Colab

If you are working in Google Colab, you can install packages using:

!pip install package_name

For example:

!pip install yfinance

After installation:

import yfinance as yf

Python Pebble

The ! tells a Colab/Jupyter notebook to execute the command through the system shell rather than as normal Python syntax.


29. Module vs Package

Let's make the difference crystal clear.

FeatureModulePackage
Basic ideaPython fileCollection of modules
Usually.py fileDirectory/folder
PurposeOrganize reusable codeOrganize larger collections of code
Examplecalculator.pyschool/
Can containFunctions, classes, variablesMultiple modules

Think:

Module = Notebook
Package = School Bag containing multiple notebooks

30. Standard Library vs Third-Party Packages

This is an important distinction.

Standard Library

These are provided with Python.

Examples:

import math
import random
import datetime
import os
import statistics

You normally don't install these using pip.

Third-Party Packages

These are developed and distributed separately.

Examples:

numpy
pandas
matplotlib
requests
yfinance

These may need to be installed using:

pip install package_name

31. Real-World Example – Student Marks Analyzer

Let's combine modules.

import statistics
import random

marks = [78, 85, 92, 67, 88]

average = statistics.mean(marks)

print("Marks:", marks)
print("Average:", average)

print("Lucky Number:", random.randint(1, 100))

Possible output:

Marks: [78, 85, 92, 67, 88]
Average: 82
Lucky Number: 47

We have used two modules in one program.


32. Real-World Example – Exam Countdown

import datetime

today = datetime.date.today()

exam_date = datetime.date(2026, 12, 1)

days_left = exam_date - today

print("Today:", today)
print("Exam Date:", exam_date)
print("Days Left:", days_left.days)

This could become the foundation of a useful Exam Countdown App.


33. Real-World Example – Random Quiz Question

Suppose we have:

import random

questions = [
    "What is Python?",
    "What is a variable?",
    "What is a module?",
    "What is a package?"
]

question = random.choice(questions)

print("Today's Question:")
print(question)

Every time the program runs, a different question may be selected.


34. A Simple Module-Based Project

Let's build a small project.

Project: Student Utility Toolkit

Folder structure:

StudentToolkit/
│
├── main.py
└── student_utils.py

student_utils.py

def percentage(marks):
    return sum(marks) / len(marks)


def highest(marks):
    return max(marks)


def lowest(marks):
    return min(marks)

main.py

import student_utils

marks = [85, 92, 76, 88, 95]

print("Average:", student_utils.percentage(marks))
print("Highest:", student_utils.highest(marks))
print("Lowest:", student_utils.lowest(marks))

Output:

Average: 87.2
Highest: 95
Lowest: 76

Congratulations!

You have just created your own reusable Python module.


35. Common Mistakes

Mistake 1: Wrong module name

import maths

when you actually wanted:

import math

Python module names must be correct.


Mistake 2: Forgetting the module name

If you write:

import math

print(sqrt(25))

you may get an error because sqrt was not imported directly.

Correct:

print(math.sqrt(25))

Or:

from math import sqrt

print(sqrt(25))

Mistake 3: Installing a standard library module

You don't normally need:

pip install math

because math is already part of Python's standard library.


Mistake 4: Naming your file after a standard module

Avoid naming your own files:

math.py
random.py
statistics.py
os.py

because your file may interfere with Python's standard modules.

Prefer names such as:

my_math.py
student_tools.py
quiz_utils.py

36. Practice Time

Level 1 – Beginner

Q1

What is a Python module?

Q2

Which statement is used to import a module?

Q3

Write the statement to import the math module.

Q4

Write a program to find the square root of 144.

Q5

Which module can be used to generate random numbers?

Q6

Write a program to generate a random number between 1 and 50.

Q7

Which module is used for dates and time?

Q8

Which module can be used to calculate the mean of a list?

Q9

What does pip do?

Q10

What is the difference between a module and a package?


37. Level 2 – Coding Practice

Q11

Write a program using math to calculate the area of a circle.

Input:

Radius = 7

Q12

Generate five random numbers between 1 and 100.


Q13

Create a program that randomly selects one student from:

["Aman", "Riya", "Raman", "Neha", "Arjun"]

Q14

Write a program that calculates the number of days between two dates.


Q15

Use the statistics module to calculate:

  • Mean

  • Median

  • Mode

for:

[10, 20, 20, 30, 40, 20]

38. Level 3 – Create Your Own Module

Create a module:

calculator.py

with these functions:

add()
subtract()
multiply()
divide()

Then create:

main.py

and import the functions.


39. Master Challenge – Student Result Analyzer

Create a Python project using modules.

Requirements

Create:

StudentResult/
│
├── main.py
└── result_utils.py

The module should contain functions for:

average()
highest()
lowest()
percentage()
grade()

The main program should:

  1. Accept marks for five subjects.

  2. Calculate total marks.

  3. Calculate percentage.

  4. Find highest marks.

  5. Find lowest marks.

  6. Calculate average.

  7. Assign a grade.

  8. Display the result.

Bonus Challenge

Add:

random

to generate sample marks for testing.


40. Quick Revision

ConceptRemember
ModulePython file containing reusable code
importImports a module
from ... importImports selected items
mathMathematical functions
randomRandom values and choices
datetimeDate and time
osOperating-system interaction
statisticsStatistical calculations
Own moduleA .py file created by you
PackageCollection/organization of modules
pipPython package installer

41. Python Pebble 🪨

Don't write the same code again and again.

Put reusable code into a module and use it whenever you need it.

A good Python programmer doesn't just ask:

"How do I make this program work?"

A better question is:

"How can I organize this code so that I can reuse it later?"

That is where Modules and Packages become powerful.


42. What You Learned

In this tutorial, you learned:

✅ What a module is
✅ How import works
✅ How from ... import works
✅ Built-in Python modules
✅ math
✅ random
✅ datetime
✅ os
✅ statistics
✅ Creating your own module
✅ Packages
✅ Installing packages using pip
✅ Using modules in real-world projects

The next time your Python program becomes too large, don't put everything into one file.

Break it into modules. Organize modules into packages. Reuse your code.

That's how small Python programs gradually become well-structured software projects.

Python Algorithms

  Python Algorithms for Beginners – Searching, Sorting and Essential Problem-Solving Techniques Learn Linear Search, Binary Search, Sorting ...