Skip to Content
Python Intermediate: Write Code You Won't Be Embarrassed to Share
Intermediate
0 likes
Courses
Python Intermediate: Write Code You Won't Be Embarrassed to Share

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.

Course Home

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.pricing then shop.pricing.add_vat(): longest, but always clear where it came from.
  • from shop.pricing import add_vat then add_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.py imports pricing.py, and pricing.py imports orders.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.py and utils2.py are 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
Was this helpful?
​ 0 ​ 0

Comments (0)

Sign in to comment

No comments yet.