📦 Python Packages: Building Your Code City
Imagine you’re building a city made entirely of LEGO blocks. Each block is useful, but a city needs neighborhoods, streets, and districts to keep things organized. That’s exactly what Python packages do for your code!
🏘️ The Big Picture: What Are Packages?
Think of it this way:
| Real World | Python |
|---|---|
| A single LEGO block | A function |
| A small toy house | A module (.py file) |
| A whole neighborhood | A package (folder of modules) |
A package is simply a folder that contains Python files (modules) grouped together. It’s how you organize your code when your project grows bigger!
🏗️ Creating Packages
It’s as easy as making a new folder!
Let’s say you’re building a game. You might organize it like this:
my_game/
__init__.py
player.py
enemies.py
weapons/
__init__.py
sword.py
bow.py
The Recipe:
- Create a folder with your package name
- Add an
__init__.pyfile inside it - Add your Python modules (
.pyfiles)
That’s it! You just created a package! 🎉
Quick Example:
# File: my_game/player.py
def create_player(name):
return {"name": name, "health": 100}
Now you can use it:
from my_game import player
hero = player.create_player("Luna")
print(hero)
# {'name': 'Luna', 'health': 100}
📜 The __init__.py File
What Is It?
The __init__.py file is like a welcome sign for your package. It tells Python: “Hey! This folder is a package, not just a random folder!”
The Magic Part
This file can be completely empty—and it still works! But you can also put code in it to make your package easier to use.
graph TD A["Folder: my_game"] --> B["__init__.py"] A --> C["player.py"] A --> D["enemies.py"] B --> E["Tells Python: I'm a package!"]
Empty vs. Filled
Empty __init__.py:
# Nothing here—just exists!
Smart __init__.py:
# my_game/__init__.py
from .player import create_player
from .enemies import spawn_enemy
# Now users can do this:
# from my_game import create_player
When you add imports to __init__.py, users get a shortcut. Instead of digging through files, they import directly from the package!
🧭 Absolute Imports
The Full Address
Absolute imports use the complete path from the top of your project. It’s like giving someone your full home address:
“123 Oak Street, Maple City, Sunshine Country”
# Always starts from the top-level package
from my_game.weapons.sword import swing
from my_game.player import create_player
When to Use Absolute Imports
✅ Your code is clear about where things come from ✅ Works anywhere in your project ✅ Recommended by Python style guides (PEP 8)
Example:
# File: my_game/battle.py
# Absolute import - full path
from my_game.weapons.sword import swing
from my_game.player import create_player
def start_battle():
hero = create_player("Aria")
swing()
🔄 Relative Imports
The Shortcut Directions
Relative imports use dots to say “look nearby!” It’s like saying:
“Go next door” instead of the full address.
| Symbol | Meaning |
|---|---|
. |
Current package (same folder) |
.. |
Parent package (one folder up) |
... |
Grandparent (two folders up) |
Example Time!
my_game/
__init__.py
player.py
weapons/
__init__.py
sword.py
bow.py
Inside my_game/weapons/sword.py:
# One dot = same folder (weapons)
from .bow import shoot_arrow
# Two dots = parent folder (my_game)
from ..player import create_player
The Golden Rule
⚠️ Relative imports only work inside packages!
You can’t use them in a script you run directly. They’re for files that are part of a package.
graph TD A["my_game"] --> B["weapons folder"] B --> C["sword.py"] B --> D["bow.py"] C -->|"from .bow"| D C -->|"from ..player"| E["player.py"] A --> E
📋 The __all__ Variable
The Guest List
Imagine you’re throwing a party and you make a list of who’s invited. The __all__ variable is exactly that—a guest list for your module!
It controls what gets imported when someone uses:
from my_module import *
How It Works
# File: my_game/player.py
__all__ = ['create_player', 'Player']
def create_player(name):
return {"name": name}
class Player:
pass
def _secret_function():
# This WON'T be imported with *
pass
def helper_function():
# This also WON'T be imported
# (not in __all__)
pass
The Result
from my_game.player import *
# ✅ create_player is available
# ✅ Player is available
# ❌ _secret_function is NOT available
# ❌ helper_function is NOT available
Why Use __all__?
- Control what users see — Hide messy internal code
- Clear public API — Tell users “these are the important things”
- Cleaner imports — Prevent namespace pollution
Pro Tip
Even if you don’t use from x import * yourself, defining __all__ is good practice. It documents your module’s public interface!
🎯 Putting It All Together
Let’s build a mini package from scratch:
calculator/
__init__.py
basic.py
advanced.py
calculator/basic.py:
__all__ = ['add', 'subtract']
def add(a, b):
return a + b
def subtract(a, b):
return a - b
def _internal_check(x):
# Hidden helper
return x > 0
calculator/advanced.py:
__all__ = ['power', 'sqrt']
def power(base, exp):
return base ** exp
def sqrt(n):
return n ** 0.5
calculator/init.py:
# Make common functions easy to access
from .basic import add, subtract
from .advanced import power, sqrt
__all__ = ['add', 'subtract',
'power', 'sqrt']
Using your package:
# Method 1: Direct from package
from calculator import add, sqrt
print(add(5, 3)) # 8
print(sqrt(16)) # 4.0
# Method 2: Import module
from calculator.basic import subtract
print(subtract(10, 4)) # 6
# Method 3: Star import (uses __all__)
from calculator import *
print(power(2, 8)) # 256
🌟 Quick Summary
| Concept | What It Does | Remember It As |
|---|---|---|
| Package | Folder with __init__.py |
A neighborhood of code |
__init__.py |
Makes folder a package | The welcome sign |
| Absolute Import | Full path from project root | Full home address |
| Relative Import | Dots for nearby modules | “Next door” directions |
__all__ |
Controls * imports |
The VIP guest list |
🚀 You Did It!
You now understand how Python organizes code at scale! Packages might seem like extra work at first, but they’re what make large projects possible.
Start small—create a folder, add __init__.py, and you’re officially a package architect! 🏛️
“Great code is organized code. And organized code lives in packages.”
