Free Study Material
Every program in this unit so far has used only Python's own built-in functions. A module is a file of pre-written Python code you can bring into your own program — this topic covers how to actually bring one in.
A module is a file containing ready-made functions and values, grouped around a common purpose (the next three topics cover three specific ones: math, random, statistics). Python offers several ways to bring a module's contents into your program:
module_name.function_name(...).import math
print(math.sqrt(25))
import statistics as stats
print(stats.mean([10, 20, 30]))
from math import factorial
print(factorial(5))
import math brings in the whole math module, so its sqrt() function is called as math.sqrt(25), giving 5.0. import statistics as stats brings in the whole statistics module under the shorter name stats, so mean() is called as stats.mean([10, 20, 30]), giving 20. from math import factorial brings in only factorial directly — it's then called on its own, factorial(5), without needing math. in front, giving 120.
Warning:from module import *brings in everything with no prefix at all, which can silently overwrite one of your own variables or functions if it happens to share a name with something inside the module — importing only the specific names you actually need (from module import name) avoids this risk entirely.
import module_name (with the prefix) is the safest default specifically because the prefix makes it immediately clear, everywhere in your code, exactly which module a function came from — this becomes genuinely important once a program imports more than one module.
A module is a file of ready-made code, brought in with import module_name (prefixed access), import module_name as alias (a shorter prefix), from module_name import name (direct access to one specific name), or from module_name import * (direct access to everything — riskier, since it can silently clash with your own names).
A Module is simply a Python file (.py) containing variables, functions, and classes that you can include in your program.
| Style | Code | How to Use |
|---|---|---|
| Standard | import math | math.pi |
| Specific | from math import pi | pi |
| Alias | import math as m | m.pi |
# Style 1: Full Import (Safest)
import math
print("Value of Pi (Style 1):", math.pi)
# Style 2: Specific Import (Cleanest)
from math import sqrt
print("Square root of 25:", sqrt(25))
# Style 3: Alias (Laziest/Fastest)
import math as m
print("Factorial of 5:", m.factorial(5))
The math module is the most commonly used module in this course — it provides mathematical functions and constants that Python's built-in operators alone don't cover.
x.x raised to the power y (like x ** y, but as a module function).x up to the nearest whole number.x down to the nearest whole number.x (x!).3.14159...), used as a value, not called with ().import math
print(math.sqrt(49))
print(math.pow(2, 5))
print(math.ceil(4.2))
print(math.floor(4.8))
print(math.factorial(4))
print(math.pi)
math.sqrt(49) gives 7.0. math.pow(2, 5) gives 32.0 — note that pow() always returns a float, unlike the * operator, which returns an int when both of its inputs are integers. math.ceil(4.2) rounds up to 5; math.floor(4.8) rounds down to 4 — notice both move 4.2 and 4.8 towards different* whole numbers, since one always rounds up and the other always rounds down, regardless of which whole number is actually closer. math.factorial(4) gives 24 (4 × 3 × 2 × 1). math.pi prints 3.141592653589793 — Python's closest possible float approximation of π, used directly as a constant, with no () needed since it isn't a function.
Note:math.pow(2, 5)always returns a float (32.0); the built-inoperator,2 5, returns an int (32) when both operands are integers. Both compute the same value, but their result types differ.
ceil() and floor() are easy to mix up because both are "rounding" functions, but they always move in one fixed direction each, regardless of how close the value already is to a whole number — ceil() always rounds up, even for 4.01; floor() always rounds down, even for 4.99. Neither one rounds to the nearest whole number the way everyday rounding does.
The math module provides sqrt(), pow() (always returns a float), ceil() (always rounds up), floor() (always rounds down), factorial(), and the constant pi — every function needs the math. prefix unless imported directly with from math import name.
math.pi: Returns the value of π (3.14159...). Used for circle calculations.math.e: Returns the value of Euler’s number (2.71828...). Used in exponential growth/decay.import math
print("Value of Pi:", math.pi)
print("Area of circle (r=5):", math.pi * 5 * 5) # 78.539...
math.ceil(x)
Rounds UP to the nearest integer.
Think: "Ceiling" is above you.
math.floor(x)
Rounds DOWN to the nearest integer.
Think: "Floor" is below you.
# Rounding Examples
x = 5.9
y = 5.1
print("Floor of 5.9:", math.floor(x)) # Output: 5
print("Ceil of 5.1:", math.ceil(y)) # Output: 6
# Note: For negative numbers, 'down' means more negative!
print("Floor of -3.2:", math.floor(-3.2)) # Output: -4
math.pow(x, y): Returns x raised to the power of y ($x^y$). Note that unlike the ** operator, this always returns a float.math.sqrt(x): Returns the square root of x ($\sqrt{x}$).math.fabs(x): Returns the absolute value (removes the negative sign). Always returns a float.# Power and Roots
print(math.pow(2, 3)) # 8.0 (Float)
print(math.sqrt(49)) # 7.0
# Absolute Value
print(math.fabs(-10)) # 10.0
print(math.fabs(10)) # 10.0
Python's trig functions DO NOT accept Degrees (like 90° or 180°).
They expect the angle in RADIANS.
# Trigonometry Example: Calculate Sin(30)
# We know Sin(30 degrees) should be 0.5
# Wrong Way
print(math.sin(30)) # Output: -0.988... (Incorrect!)
# Correct Way
angle_in_degrees = 30
angle_in_radians = math.radians(angle_in_degrees)
print(math.sin(angle_in_radians)) # Output: 0.4999... (Correct)
Every value in every program so far has been completely predictable — the same code always produces the same result. The random module breaks that deliberately, generating unpredictable values on purpose.
0.0 up to (but never including) 1.0.a and b, both included.start up to (not including) stop, following the exact same "stop excluded" rule as range().Every one of these genuinely returns a different value on different runs — there is no fixed, single correct output to check against.
import random
dice_roll = random.randint(1, 6)
print("Dice roll:", dice_roll)
print(1 <= dice_roll <= 6)
fruits = ["apple", "banana", "mango", "grape"]
picked = random.choice(fruits)
print("Picked:", picked)
print(picked in fruits)
random.randint(1, 6) returns a whole number from 1 to 6, inclusive — a different value on each run, but always somewhere in that exact range, which is exactly what 1 <= dice_roll <= 6 confirms by printing True every single time, regardless of which specific number was rolled. random.choice(fruits) picks one element from fruits — again different each run, but always genuinely one of the four fruits, which picked in fruits confirms the same way, always printing True.
Note: This program's exact printed values (the dice number, the fruit name) change every time you run it — that's the module working correctly, not a bug. What stays fixed and checkable is the range the value falls in, which is exactly what this worked example checks instead of a specific number.
Because random's output genuinely changes every run, a program using it needs a different way to confirm it's working correctly than tracing a specific expected value — checking that the result always satisfies a known condition (like 1 <= dice_roll <= 6) is that alternative, and it's exactly how this module's own examples above are verified.
random.random() gives a random float below 1.0; random.randint(a, b) gives a random whole number including both ends; random.randrange(start, stop) excludes stop, like range(); random.choice(sequence) picks one random element. All four genuinely vary between runs by design — a program using them is checked by confirming the result satisfies a known condition, not by tracing one fixed expected value.
Since computers are logical, they cannot be truly random (like rolling a physical die).
Python uses a Seed Number (usually based on the current time) and runs it through a complex mathematical formula to produce a stream of numbers that appears random.
0.0 <= N < 1.0import random
# Generate a random float
val = random.random()
print("Random Float:", val)
# Output: 0.732... (Changes every time)
# Trick: Scaling it to 0-100 (e.g., for a percentage chance)
print("Percentage:", val * 100)
Returns a random integer N such that a <= N <= b.
⚠️ CRITICAL NOTE: Unlike standard Python ranges, this function INCLUDES the endpoint 'b'.
# Rolling a standard dice
roll = random.randint(1, 6)
print("You rolled a:", roll)
# Possible Outputs: 1, 2, 3, 4, 5, 6
randrange(start, stop, step)# Pick a random even number less than 10
num = random.randrange(0, 10, 2)
print("Random Even Number:", num)
# Possible Outputs: 0, 2, 4, 6, 8 (Never 10!)
| Function | Code | Range Interval | Includes Endpoint? |
|---|---|---|---|
| randint | randint(1, 10) | [1, 10] | YES |
| randrange | randrange(1, 10) | [1, 10) | NO |
You've already summarised a list using min(), max(), and sum(). The statistics module goes further, providing the standard statistical measures CBSE expects by name.
data is sorted (the average of the two middle values, if there's an even count).data can be a list or a tuple of numbers.
import statistics
marks = [67, 85, 92, 67, 74]
print(statistics.mean(marks))
print(statistics.median(marks))
print(statistics.mode(marks))
statistics.mean(marks) adds all five values (67 + 85 + 92 + 67 + 74 = 385) and divides by 5, giving 77. statistics.median(marks) first sorts the data ([67, 67, 74, 85, 92]) and takes the middle value — the third of five — giving 74. statistics.mode(marks) returns 67, since it's the only value that occurs more than once (twice, while every other value occurs just once).
Warning:statistics.mode()raises aStatisticsErrorif every value in the data occurs exactly the same number of times — there's no single "most common" value to return.mode()is only safe to call when at least one value is known to repeat more often than the rest.
median()'s definition depends on sorted order, not the order data was originally given in — statistics.median() sorts internally before picking the middle value, so the caller never needs to sort the data first, unlike a hand-written median calculation that would need that step done explicitly.
The statistics module provides mean() (average), median() (the middle value once sorted), mode() (the most frequent value), and stdev() (spread from the mean) — all built specifically for statistical summaries, complementing the more general min()/max()/sum() already used with lists and tuples.
| Function | Definition | Example: [1, 2, 2, 10] |
|---|---|---|
| mean() | Average | (1+2+2+10) / 4 = 3.75 |
| median() | Middle Value |
Sorted: 1, 2, 2, 10 Result: 2 |
| mode() | Most Common |
'2' appears twice. Result: 2 |
import statistics
data = [10, 20, 30, 40]
avg = statistics.mean(data)
print("Average:", avg)
# Output: 25.0
# Case 1: Odd number of items
scores_1 = [1, 5, 9]
print("Median 1:", statistics.median(scores_1))
# Output: 5
# Case 2: Even number of items (Middle are 5 and 7)
scores_2 = [1, 5, 7, 100]
print("Median 2:", statistics.median(scores_2))
# Output: 6.0 (Average of 5 and 7)
What if there is a tie? (e.g., [1, 1, 2, 2])?
StatisticsError.votes = ["Red", "Blue", "Red", "Green", "Red"]
winner = statistics.mode(votes)
print("Winner:", winner)
# Output: 'Red'
A working recap of this chapter — importing a module, and using one function from each of the three modules covered — closing out this unit's very last topic.
import module_name (prefixed access) or from module_name import name (direct access to one name).sqrt(), pow(), ceil(), floor(), factorial(), the constant pi.random(), randint(a, b), randrange(start, stop), choice(sequence) — genuinely different results each run.mean(), median(), mode(), stdev().import math
import random
import statistics
marks = [78, 85, 92, 67, 74]
print("Average marks:", statistics.mean(marks))
print("Square root of highest mark:", math.sqrt(max(marks)))
topper_index = random.randint(0, len(marks) - 1)
print("Randomly selected mark:", marks[topper_index])
print("Is a valid mark from the list:", marks[topper_index] in marks)
statistics.mean(marks) gives 79.2 — the same total-then-divide calculation, this time computed by the module instead of by hand. math.sqrt(max(marks)) combines a built-in function (max()) with a module function (math.sqrt()) in a single line — max(marks) is 92, so this prints math.sqrt(92)'s result. random.randint(0, len(marks) - 1) generates a valid index for marks (from 0 to 4, since len(marks) - 1 is 4) — a different index each run, but marks[topper_index] in marks still always prints True, since whatever index is picked genuinely comes from that list.
Tip:random.randint(0, len(marks) - 1)is the standard pattern for picking a valid random position in any list —len(marks) - 1is always the list's last valid index, exactly as covered when list indexing was first introduced.
This closing example deliberately combines all three modules with material from earlier chapters — max() on a list, an index expression, membership with in — because that's exactly how modules are actually used in practice: alongside everything else already learned, not in isolation.
A module is brought in with import or from ... import; math provides numeric functions and the constant pi; random generates unpredictable values within a known range; statistics provides mean(), median(), mode(), and stdev() — closing out this unit's full progression from Python's basic syntax through control flow, loops, strings, and all three collection types.
A Module is a file containing pre-written code (functions and variables) that you can re-use. Think of Python as an empty desk, and a Module as a Toolbox. You must open (Import) the toolbox before you can use the hammer inside.
| Style | Code | Usage Example | Best For... |
|---|---|---|---|
| Standard | import math |
math.sqrt(4) |
Safety (No name clashes) |
| Specific | from math import sqrt |
sqrt(4) |
Convenience (Less typing) |
| Alias | import math as m |
m.sqrt(4) |
Speed (Short nickname) |
Rule: Standard mathematical operations.
Import: import math
| Function | Description | Example Input → Output |
|---|---|---|
| math.ceil(x) | Rounds UP to nearest integer |
4.1 → 5
|
| math.floor(x) | Rounds DOWN to nearest integer |
4.9 → 4
|
| math.pow(x,y) | Returns $x^y$ as a Float |
2, 3 → 8.0
|
| math.sqrt(x) | Square root ($\sqrt{x}$) |
49 → 7.0
|
| math.fabs(x) | Absolute Value (Positive) |
-10 → 10.0
|
| math.sin(x) | Sine of angle (Must be Radians) |
radians(30) → 0.5
|
| Constants | math.pi, math.e |
3.14159... |