Lesson 12 - Modules & Code Reusability
Learning Objective
Split code across multiple files using modules, import functions between them, and understand what an import statement actually does.
Introduction
Every lesson so far has lived inside a single Python file.
That works well for small programs, but as software grows, putting everything into one file becomes difficult to manage.
Python solves this with modules.
A module is simply a Python file (.py) that contains code you want to reuse elsewhere.
Instead of copying and pasting functions between files, you can place them in one module and import them wherever they’re needed.
You’ve actually been using modules since Lesson 1.
For example:
from bonicbot_bridge import BonicBotHere, bonicbot_bridge is a module (technically a package made up of multiple modules), and you’re importing the BonicBot class from it.
Modules help make programs:
- Easier to organize
- Easier to maintain
- Easier to test
- Easier to reuse
What Is a Module?
Any Python file can be a module.
Example:
# helpers.py
def greet(name):
print(f"Hello, {name}!")Another file can use it:
from helpers import greet
greet("Aditi")Output:
Hello, Aditi!The function only needs to be written once.
Why Use Modules?
Keep related code together.
Example:
- math utilities
- robot controls
- data processing
Each can live in its own file.
OrganizationWrite a function once and use it in many programs.
No copy-paste required.
ReusabilityFix a bug in one place and every script that imports the module benefits.
MaintainabilityCreating Your First Module
File:
# helpers.py
def is_prime(n):
if n < 2:
return False
for divisor in range(2, n):
if n % divisor == 0:
return False
return TrueAnother file:
# main.py
from helpers import is_prime
print(is_prime(17))Output:
TrueCode
helpers.py
# helpers.py — a module: just function definitions, nothing runs on its own
def is_prime(n):
if n < 2:
return False
for divisor in range(2, n):
if n % divisor == 0:
return False
return True
def is_palindrome(word):
cleaned = word.lower()
return cleaned == cleaned[::-1]main.py
# main.py — imports and uses the module above
from helpers import is_prime, is_palindrome
print(is_prime(17))
print(is_palindrome("radar"))
import helpers
print(helpers.is_prime(18))Expected Output
Click to see expected output
True
True
FalseTwo Ways to Import
Import Specific Names
from helpers import is_primeUsage:
print(is_prime(17))This places is_prime directly into your current file’s namespace.
Import the Entire Module
import helpersUsage:
print(helpers.is_prime(17))The function remains grouped under the module name.
Comparing Import Styles
| Style | Example | Call Style |
|---|---|---|
| Import specific function | from helpers import is_prime | is_prime(17) |
| Import module | import helpers | helpers.is_prime(17) |
Both approaches are valid.
Choose whichever improves readability for your project.
Where Does Python Look for Modules?
When Python sees:
import helpersit searches for:
- The current folder
- Installed packages
- Python’s standard library locations
That’s why:
import mathworks immediately.
And why:
from bonicbot_bridge import BonicBotworks after the SDK has been installed.
Reusing Code Across Projects
One of the biggest advantages of modules is that they encourage reusable code.
Instead of:
# project_a.py
# copy function here
# project_b.py
# copy function againyou can write:
# helpers.pyonce and import it everywhere.
This eliminates duplication and reduces maintenance work.
🔧 Under the Hood
What’s the difference between “from helpers import is_prime” and “import helpers”?
Both statements load the same module.
The difference is how names become available afterward.
Option 1
from helpers import is_primePython:
- Loads
helpers.py - Finds
is_prime - Places it directly into the current namespace
You can call:
is_prime(17)without mentioning helpers.
Option 2
import helpersPython:
- Loads
helpers.py - Keeps everything grouped under
helpers
You call:
helpers.is_prime(17)instead.
Important Detail
Python only executes a module once.
If multiple files import:
import helpersPython loads it the first time and then reuses the already-loaded version.
This helps imports stay efficient.
Module Discovery
When Python imports:
import helpersit first looks for:
helpers.pyin the same folder.
If it isn’t found there, Python searches installed packages and standard library locations.
This is exactly how packages such as:
math
random
pathlib
bonicbot_bridgeare discovered.
Student Challenge
Challenge 1
Build a reusable statistics module named stats.py with helper functions, and import them into a main reporting script report.py.
- In
stats.py, define two functions:mean(numbers): Calculates and returns the average of a list of numbers.max_value(numbers): Finds and returns the highest value in a list.
- In
report.py, importmeanandmax_valuefromstats, pass in a list of test scores (such as[82, 91, 76, 88, 95]), and print the average (86.4) and highest score (95).
Hint
Notice that neither function in stats.py references scores directly.
They operate on whatever list is passed in as an argument, making them completely reusable for any collection of numbers across different projects.
Click to see solution
stats.py
# stats.py
def mean(numbers):
return sum(numbers) / len(numbers)
def max_value(numbers):
highest = numbers[0]
for n in numbers[1:]:
if n > highest:
highest = n
return highestreport.py
# report.py
from stats import mean, max_value
scores = [82, 91, 76, 88, 95]
print(f"Average: {mean(scores):.1f}")
print(f"Highest: {max_value(scores)}")Expected Output:
Average: 86.4
Highest: 95Challenge 2
Create a custom robot movement module named robot_moves.py and import its functions into a main control script challenge_use_robot_moves.py.
- In
robot_moves.py, define functions for robot actions:patrol_square(bot, side_m=0.4, speed=0.2): Drives in a square using loops.scan_surroundings(bot): Scans left/right with obstacle distance checks and returns a dictionary of readings.wave_hello(bot): Moves arm or head servos to greet.
- In
challenge_use_robot_moves.py, importpatrol_square,scan_surroundings, andwave_hellofromrobot_moves, and run them inside aBonicBotcontext block.
Full SDK method details are available in the Python SDK reference.
Hint
Any function defined in:
robot_moves.pycan immediately be imported in another script using:
from robot_moves import wave_helloas long as both files are in the same folder. No extra configuration is required.
Click to see solution
robot_moves.py
# robot_moves.py
def patrol_square(bot, side_m=0.4, speed=0.2):
for _ in range(4):
bot.drive_distance(side_m, speed=speed)
bot.rotate_angle(90, speed=45.0)
bot.stop()
def scan_surroundings(bot):
bot.look_left()
left_distance = bot.get_min_obstacle_distance()
bot.look_right()
right_distance = bot.get_min_obstacle_distance()
bot.look_center()
return {
"left": left_distance,
"right": right_distance
}
def wave_hello(bot):
print("Waving hello!")
bot.move_left_arm(shoulder=90, elbow=30)
bot.move_left_arm(shoulder=90, elbow=0)
bot.move_left_arm(shoulder=0, elbow=0)challenge_use_robot_moves.py
# challenge_use_robot_moves.py
from bonicbot_bridge import BonicBot
from robot_moves import patrol_square, scan_surroundings, wave_hello
with BonicBot(host='192.168.0.188') as bot:
wave_hello(bot)
readings = scan_surroundings(bot)
print(f"Obstacle readings: {readings}")
patrol_square(bot, side_m=0.3)Common Module Structure
A small project might look like:
project/
│
├── main.py
├── helpers.py
├── stats.py
└── robot_moves.pyEach file has a clear responsibility.
This organization becomes increasingly important as projects grow.
Reflection Question
robot_moves.pyis a module you wrote yourself, andbonicbot_bridgeis a module BonicBot Robotics wrote — but both get imported with the exact samefrom ... import ...syntax. What does that tell you about what an SDK or library actually is, underneath the name?
By the end of this lesson, you should be comfortable creating modules, importing functions between files, choosing between different import styles, and organizing reusable code into separate, maintainable components.