Python Modules and Packages: Splitting One Big File
When one script gets too long, split it into modules and packages. After this, you can move functions into their own files, import them, and keep the entry point small.
Course content
Sign in to save your progress.
-
Set Up Projects That Don't Break Each Other
-
Python Virtual Environments and pip: One Project, One Environment
-
Pinning Python Dependencies With requirements.txt
-
-
-
Organize Code Other People Can Read
-
Python Modules and Packages: Splitting One Big File
-
Python Imports: Why ModuleNotFoundError Keeps Happening
-
Python Classes: When a Dictionary Is No Longer Enough
-
-
-
Work With Real Files
-
Python File Handling: Open, Read, Write, and Always Use with
-
Python pathlib: Stop Building File Paths by Hand
-
Reading, Cleaning and Writing CSV Data in Python
-
-
-
Shorter Code That Still Says What It Does
-
Python Comprehensions: Lists, Sets and Dictionaries
-
When a Comprehension Should Be a Plain Loop
-
-
-
Prove It Works Before Someone Else Finds Out
-
Python Testing Basics With pytest
-
Debugging Python With print, logging and pdb
-
-
- Final Check: Python Intermediate
A module is just a .py file. A package is a folder of modules. Splitting a long script into modules doesn't make it run any differently. It makes it possible for a person to find things, which matters more than it sounds once the file passes a few hundred lines.
Skip ahead: If you already split projects into packages with an __init__.py and use if __name__ == "__main__":, continue to "Python Imports: Why ModuleNotFoundError Keeps Happening."
Why this matters
One big file works fine until you need to change something. Then you scroll. You search. You find two functions with almost the same name and don't know which one is used. Someone else opens the file and gives up. Splitting by topic means the file name already tells you where to look: price rules in pricing.py, reading files in storage.py.
Do you need this for a 60-line script? No. Splitting too early just gives you five tiny files to jump between. A reasonable trigger: when you can't describe the file in one sentence without the word "and", or when you want to reuse a function from it in a second script.
Step 1: move functions into a module
Say your script has price logic mixed with everything else. Move the price functions into their own file:
# pricing.py
VAT_RATE = 0.12 # example rate for this exercise
def add_vat(amount):
return round(amount * (1 + VAT_RATE), 2)
def apply_discount(amount, percent):
return round(amount * (100 - percent) / 100, 2)
Then import it from the main script in the same folder:
# main.py
import pricing
subtotal = 1500
discounted = pricing.apply_discount(subtotal, 10)
print("After discount:", discounted)
print("With VAT:", pricing.add_vat(discounted))
After discount: 1350.0
With VAT: 1512.0
import pricing runs pricing.py once and gives you its names under pricing.. Writing pricing.add_vat instead of just add_vat is a little longer, but anyone reading main.py can see where the function comes from.
Step 2: protect code that should only run directly
A common problem: you put test prints at the bottom of pricing.py, and now they run every time something imports it. The fix is the __name__ check:
# pricing.py
VAT_RATE = 0.12 # example rate for this exercise
def add_vat(amount):
return round(amount * (1 + VAT_RATE), 2)
def apply_discount(amount, percent):
return round(amount * (100 - percent) / 100, 2)
if __name__ == "__main__":
# Only runs with: python pricing.py
print(add_vat(100))
python3 pricing.py
python3 main.py
112.0
After discount: 1350.0
With VAT: 1512.0
When you run a file directly, Python sets its __name__ to "__main__". When it is imported, __name__ is the module name, "pricing". So the block runs in the first case and is skipped in the second. Use it for any file that is both a module and a script.
Step 3: group modules into a package
When you have several related modules, put them in a folder. Here is a small project for an online shop's order report:
shop_report/
├── main.py
└── shop/
├── __init__.py
├── pricing.py
└── orders.py
mkdir -p shop && mv pricing.py shop/ && touch shop/__init__.py
# shop/orders.py
from shop.pricing import apply_discount, add_vat
def order_total(items, discount_percent=0):
subtotal = sum(price * qty for price, qty in items)
return add_vat(apply_discount(subtotal, discount_percent))
# main.py
from shop.orders import order_total
items = [(250.0, 2), (1000.0, 1)]
print(order_total(items))
print(order_total(items, discount_percent=10))
1680.0
1512.0
__init__.py marks the folder as a regular package. It can be empty. Python 3 can import folders without it (called namespace packages), but leaving it out causes confusing behaviour with some tools, so add it.
import X or from X import Y?
import shop.pricingthenshop.pricing.add_vat(): longest, but always clear where it came from.from shop.pricing import add_vatthenadd_vat(): shorter. Fine when the name is clear on its own.from shop.pricing import *: imports everything. Avoid it. You can't tell where a name came from, and two modules with the same function name silently overwrite each other.
⚠ Warning: Don't name your own module after a standard library or installed module, like random.py, csv.py, email.py or requests.py. Python finds your file first, so import random imports your file instead of the real one, and the error appears somewhere that has nothing to do with the name. The next lesson shows why.
Common mistakes
- Circular imports.
orders.pyimportspricing.py, andpricing.pyimportsorders.py. Python fails with "partially initialized module". Usually it means a shared function belongs in a third module that both import. - Splitting by file size instead of topic.
utils1.pyandutils2.pyare not organization. Name modules after what they do. - Doing work at import time. A module that connects to a database or reads a big file at the top level does it on every import. Put that work in functions.
💡 Tip: Keep main.py short: read the input, call functions from your package, show the result. If the main script is mostly logic, the logic hasn't found its module yet.
What happens if you skip this step
The single file keeps growing, because adding to it is always easier than splitting it. Eventually it is 2,000 lines, nobody wants to touch it, and every change risks breaking something unrelated three screens away. Splitting it then is a big, risky job. Splitting it a little at a time costs almost nothing.
Open your longest script. Could you describe what each part does in one sentence, and would those sentences make good file names?
About
When one script gets too long, split it into modules and packages. After this, you can move functions into their own files, import them, and keep the entry point small.
- Duration
- 5 min
- Last update
- 09/17/2026
Comments (0)
Sign in to commentNo comments yet.