Prerequisites
- Basic understanding of programming concepts ๐
- Python installation (3.8+) ๐
- VS Code or preferred IDE ๐ป
What you'll learn
- Understand the concept fundamentals ๐ฏ
- Apply the concept in real projects ๐๏ธ
- Debug common issues ๐
- Write clean, Pythonic code โจ
๐ฏ Introduction
Welcome to this exciting tutorial on Python Path and Module Search! ๐ In this guide, weโll explore how Python finds and imports modules, one of the most fundamental aspects of Python programming.
Youโll discover how Pythonโs module search mechanism works, allowing you to organize code into reusable components. Whether youโre building web applications ๐, data science projects ๐, or automation scripts ๐ค, understanding how Python finds modules is essential for writing maintainable, scalable code.
By the end of this tutorial, youโll feel confident managing Python paths and creating well-organized projects! Letโs dive in! ๐โโ๏ธ
๐ Understanding Python Path and Module Search
๐ค What is Python Path?
Python path is like a treasure map ๐บ๏ธ that Python uses to find modules. Think of it as a GPS system that helps Python navigate through your computer to locate the code you want to import.
In Python terms, the module search path is a list of directories where Python looks for modules when you use the import
statement. This means you can:
- โจ Import modules from multiple locations
- ๐ Organize code into logical packages
- ๐ก๏ธ Avoid naming conflicts between modules
๐ก Why Understanding Python Path Matters?
Hereโs why developers need to master Pythonโs module search:
- Project Organization ๐: Structure code into clean, manageable modules
- Code Reusability โป๏ธ: Share code between different projects
- Debugging Import Errors ๐: Quickly fix โModuleNotFoundErrorโ
- Package Development ๐ฆ: Create and distribute your own Python packages
Real-world example: Imagine building a recipe app ๐ณ. With proper module organization, you can separate ingredients, cooking methods, and recipe storage into different modules that work together seamlessly!
๐ง Basic Syntax and Usage
๐ Viewing the Python Path
Letโs start by exploring Pythonโs module search path:
# ๐ Hello, Python Path!
import sys
# ๐ View the current Python path
print("Python will search for modules in these locations:")
for i, path in enumerate(sys.path, 1):
print(f"{i}. ๐ {path}")
# ๐จ The first item is usually the current directory
print(f"\nโจ Current script directory: {sys.path[0]}")
๐ก Explanation: sys.path
is a list containing all directories where Python searches for modules. The search happens in order - Python checks each directory until it finds the module!
๐ฏ How Module Search Works
Hereโs the search process Python follows:
# ๐๏ธ Understanding import mechanics
import os
# ๐ Step 1: Python checks built-in modules
import math # โ
Found in built-ins!
# ๐ Step 2: Python checks sys.path directories
# Let's create a simple module
module_content = '''
# ๐ฎ game_utils.py - A fun game utilities module!
def roll_dice():
"""Roll a six-sided dice ๐ฒ"""
import random
return random.randint(1, 6)
def get_player_emoji(player_number):
"""Get emoji for player ๐ฏ"""
emojis = ["๐ฆธ", "๐ง", "๐ฆน", "๐ง", "๐ฆพ"]
return emojis[player_number % len(emojis)]
'''
# ๐พ Save our module
with open('game_utils.py', 'w') as f:
f.write(module_content)
# ๐ฏ Now we can import it!
import game_utils
print(f"Dice roll: {game_utils.roll_dice()} ๐ฒ")
print(f"Player 1: {game_utils.get_player_emoji(1)}")
๐ Modifying Python Path
You can add directories to Pythonโs search path:
# ๐ ๏ธ Adding custom directories to sys.path
import sys
import os
# ๐ Create a custom modules directory
custom_path = os.path.join(os.getcwd(), 'my_modules')
os.makedirs(custom_path, exist_ok=True)
# โ Add it to Python path
sys.path.append(custom_path)
print(f"โ
Added {custom_path} to Python path!")
# ๐จ Now modules in my_modules/ can be imported
# Create a test module
test_module = '''
# ๐ awesome_tools.py
def celebrate():
return "๐ Success! You've mastered Python paths! ๐"
'''
module_path = os.path.join(custom_path, 'awesome_tools.py')
with open(module_path, 'w') as f:
f.write(test_module)
# ๐ฏ Import from our custom path
import awesome_tools
print(awesome_tools.celebrate())
๐ก Practical Examples
๐ Example 1: E-commerce Module System
Letโs build a modular e-commerce system:
# ๐๏ธ Project structure for our shop
import os
import sys
# ๐ Create project structure
def create_shop_structure():
"""Create an organized shop module structure ๐ช"""
# ๐๏ธ Define our structure
structure = {
'shop': {
'__init__.py': '# ๐ Shop package',
'products.py': '''
# ๐ฆ Product management module
class Product:
def __init__(self, name, price, emoji):
self.name = name
self.price = price
self.emoji = emoji
def display(self):
return f"{self.emoji} {self.name} - ${self.price:.2f}"
# ๐จ Product catalog
PRODUCTS = [
Product("Python Book", 29.99, "๐"),
Product("Coffee Mug", 12.99, "โ"),
Product("Keyboard", 79.99, "โจ๏ธ"),
Product("Mouse Pad", 9.99, "๐ฑ๏ธ")
]
''',
'cart.py': '''
# ๐ Shopping cart module
class ShoppingCart:
def __init__(self):
self.items = []
print("๐ Created new shopping cart!")
def add_item(self, product, quantity=1):
self.items.append({
'product': product,
'quantity': quantity
})
print(f"โ
Added {quantity}x {product.display()}")
def get_total(self):
total = sum(item['product'].price * item['quantity']
for item in self.items)
return total
def checkout(self):
print("\\n๐๏ธ Your Order:")
for item in self.items:
product = item['product']
qty = item['quantity']
subtotal = product.price * qty
print(f" {product.display()} x{qty} = ${subtotal:.2f}")
print(f"\\n๐ฐ Total: ${self.get_total():.2f}")
print("โจ Thanks for shopping! ๐")
''',
'utils': {
'__init__.py': '# ๐ง Utilities package',
'discounts.py': '''
# ๐ท๏ธ Discount calculations
def apply_discount(price, discount_percent):
"""Apply percentage discount ๐ธ"""
discount = price * (discount_percent / 100)
final_price = price - discount
print(f"๐ฏ {discount_percent}% off! Save ${discount:.2f}")
return final_price
def get_seasonal_discount():
"""Get current seasonal discount ๐"""
import datetime
month = datetime.datetime.now().month
# ๐ Holiday discounts!
if month == 12: # December
return 25 # 25% off!
elif month in [6, 7, 8]: # Summer
return 15 # 15% off!
else:
return 10 # Regular 10% off
'''
}
}
}
# ๐๏ธ Create the structure
for root_dir, contents in structure.items():
create_directory_structure(root_dir, contents)
print("โ
Shop module structure created!")
def create_directory_structure(base_path, contents):
"""Recursively create directory structure ๐"""
os.makedirs(base_path, exist_ok=True)
for name, content in contents.items():
path = os.path.join(base_path, name)
if isinstance(content, dict):
# ๐ It's a subdirectory
create_directory_structure(path, content)
else:
# ๐ It's a file
with open(path, 'w') as f:
f.write(content)
# ๐ Create our shop!
create_shop_structure()
# ๐ฎ Now let's use our modular shop
from shop.products import PRODUCTS
from shop.cart import ShoppingCart
from shop.utils.discounts import apply_discount, get_seasonal_discount
# ๐ Start shopping!
cart = ShoppingCart()
# ๐ฏ Add some items
cart.add_item(PRODUCTS[0], 2) # 2 Python books
cart.add_item(PRODUCTS[1], 1) # 1 Coffee mug
# ๐ท๏ธ Apply seasonal discount
original_total = cart.get_total()
discount = get_seasonal_discount()
final_total = apply_discount(original_total, discount)
print(f"\n๐ Final price after seasonal discount: ${final_total:.2f}")
๐ฎ Example 2: Game Module Loader
Letโs create a dynamic game module loader:
# ๐ฏ Dynamic module loading for games
import importlib
import os
import sys
class GameModuleLoader:
"""Load game modules dynamically ๐ฎ"""
def __init__(self, games_directory='games'):
self.games_dir = games_directory
self.loaded_games = {}
# ๐ Ensure games directory exists
os.makedirs(self.games_dir, exist_ok=True)
# โ Add to Python path
if self.games_dir not in sys.path:
sys.path.insert(0, self.games_dir)
print(f"๐ฎ Game Module Loader initialized!")
print(f"๐ Games directory: {os.path.abspath(self.games_dir)}")
def create_game(self, name, code):
"""Create a new game module ๐จ"""
filename = f"{name.lower().replace(' ', '_')}.py"
filepath = os.path.join(self.games_dir, filename)
with open(filepath, 'w') as f:
f.write(code)
print(f"โ
Created game: {name} ({filename})")
return filename
def load_game(self, module_name):
"""Load a game module dynamically ๐"""
try:
# ๐ Remove .py extension if present
if module_name.endswith('.py'):
module_name = module_name[:-3]
# ๐ฏ Import the module
game_module = importlib.import_module(module_name)
# ๐ Reload if already loaded
if module_name in self.loaded_games:
game_module = importlib.reload(game_module)
self.loaded_games[module_name] = game_module
print(f"โ
Loaded game: {module_name}")
return game_module
except ImportError as e:
print(f"โ Failed to load {module_name}: {e}")
return None
def list_available_games(self):
"""List all available game modules ๐"""
print("\n๐ฎ Available Games:")
for file in os.listdir(self.games_dir):
if file.endswith('.py') and not file.startswith('__'):
game_name = file[:-3].replace('_', ' ').title()
print(f" ๐ฏ {game_name} ({file})")
# ๐ฎ Let's create some games!
loader = GameModuleLoader()
# ๐ฒ Game 1: Dice Roller
dice_game = '''
# ๐ฒ Dice Rolling Game
import random
def play():
"""Roll dice and get your fortune! ๐ฐ"""
print("\\n๐ฒ Welcome to Dice Fortune!")
roll = random.randint(1, 6)
fortunes = {
1: ("๐ข", "Try again! Better luck next time!"),
2: ("๐", "Not bad, but you can do better!"),
3: ("๐", "Good roll! Things are looking up!"),
4: ("๐", "Great roll! Fortune smiles upon you!"),
5: ("๐", "Amazing! You're on fire!"),
6: ("๐", "JACKPOT! You're the champion!")
}
emoji, message = fortunes[roll]
print(f"You rolled: {roll} {emoji}")
print(f"{message}")
return roll
'''
# ๐ Game 2: Card Picker
card_game = '''
# ๐ Card Picking Game
import random
def play():
"""Pick a card and test your luck! ๐ด"""
print("\\n๐ Welcome to Lucky Card!")
suits = ["โ ๏ธ", "โฅ๏ธ", "โฆ๏ธ", "โฃ๏ธ"]
ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"]
suit = random.choice(suits)
rank = random.choice(ranks)
print(f"Your card: {rank}{suit}")
# ๐ฏ Special combinations
if rank == "A" and suit == "โ ๏ธ":
print("๐ ACE OF SPADES! Ultimate luck!")
elif rank in ["J", "Q", "K"]:
print("๐ Royalty! You're destined for greatness!")
elif suit == "โฅ๏ธ":
print("โค๏ธ Hearts! Love is in the air!")
return f"{rank}{suit}"
'''
# ๐จ Create the games
loader.create_game("Dice Fortune", dice_game)
loader.create_game("Lucky Card", card_game)
# ๐ List available games
loader.list_available_games()
# ๐ฎ Load and play games!
dice_module = loader.load_game("dice_fortune")
if dice_module:
dice_module.play()
card_module = loader.load_game("lucky_card")
if card_module:
card_module.play()
๐ Advanced Concepts
๐งโโ๏ธ Package Development with init.py
When youโre ready to create professional packages:
# ๐ฏ Advanced package structure
import os
def create_advanced_package():
"""Create a professional Python package ๐ฆ"""
package_structure = {
'awesome_toolkit': {
'__init__.py': '''
# ๐ Awesome Toolkit Package
"""A collection of awesome Python tools! โจ"""
__version__ = "1.0.0"
__author__ = "Python Master ๐ง"
# ๐ฏ Convenient imports
from .core import ToolkitCore
from .helpers import magic_function, super_helper
from .constants import MAGIC_NUMBER, EMOJI_LIST
# ๐ Define what gets imported with "from awesome_toolkit import *"
__all__ = ['ToolkitCore', 'magic_function', 'super_helper',
'MAGIC_NUMBER', 'EMOJI_LIST']
print(f"โจ Awesome Toolkit v{__version__} loaded!")
''',
'core.py': '''
# ๐ฏ Core functionality
class ToolkitCore:
"""The heart of our toolkit ๐"""
def __init__(self):
self.power_level = 9000 # ๐ฅ It's over 9000!
print("๐ ToolkitCore initialized!")
def do_magic(self):
return "โจ Magic performed! ๐ฉ"
''',
'helpers.py': '''
# ๐ ๏ธ Helper functions
def magic_function(x):
"""Apply magical transformation ๐ช"""
return x ** 2 + 42 # The answer to everything!
def super_helper(data):
"""Super helpful function ๐ฆธ"""
return f"๐ฏ Processed: {data}"
''',
'constants.py': '''
# ๐ Package constants
MAGIC_NUMBER = 42 # ๐ The answer!
EMOJI_LIST = ["๐", "โจ", "๐ฏ", "๐ก", "๐"]
DEFAULT_TIMEOUT = 30 # seconds โฑ๏ธ
''',
'utils': {
'__init__.py': '''
# ๐ง Utilities subpackage
from .validators import validate_input
from .formatters import format_output
''',
'validators.py': '''
# โ
Input validation
def validate_input(value):
"""Validate user input ๐ก๏ธ"""
if not value:
raise ValueError("โ Input cannot be empty!")
return True
''',
'formatters.py': '''
# ๐จ Output formatting
def format_output(data):
"""Format output beautifully ๐
"""
return f"๐ฆ {data} โจ"
'''
}
}
}
# ๐๏ธ Create the package
for package, contents in package_structure.items():
create_directory_structure(package, contents)
return package_structure
# ๐ฏ Create our advanced package
create_advanced_package()
# ๐ Now let's use it!
import awesome_toolkit
# โจ Use the convenient imports
toolkit = awesome_toolkit.ToolkitCore()
print(toolkit.do_magic())
# ๐ฏ Access everything we exposed
result = awesome_toolkit.magic_function(10)
print(f"Magic result: {result}")
# ๐ Check what's available
print(f"\n๐ฆ Available in awesome_toolkit:")
for item in awesome_toolkit.__all__:
print(f" โ
{item}")
๐๏ธ PYTHONPATH Environment Variable
For permanent path modifications:
# ๐ Working with PYTHONPATH
import os
import sys
import subprocess
# ๐ Check current PYTHONPATH
pythonpath = os.environ.get('PYTHONPATH', 'Not set')
print(f"๐ Current PYTHONPATH: {pythonpath}")
# ๐ฏ Demonstrate PYTHONPATH usage
def demonstrate_pythonpath():
"""Show how PYTHONPATH affects module search ๐"""
# ๐ Create a test structure
test_dir = 'pythonpath_demo'
os.makedirs(test_dir, exist_ok=True)
# ๐จ Create a module
module_content = '''
# ๐ special_module.py
def greet():
return "๐ Hello from PYTHONPATH module!"
'''
with open(os.path.join(test_dir, 'special_module.py'), 'w') as f:
f.write(module_content)
# ๐งช Test 1: Without PYTHONPATH
print("\n๐งช Test 1: Importing without PYTHONPATH")
try:
import special_module
print("โ
Imported successfully!")
except ImportError:
print("โ Import failed (expected)")
# ๐งช Test 2: With PYTHONPATH
print("\n๐งช Test 2: Importing with PYTHONPATH")
# ๐ง Create a test script
test_script = '''
import sys
print(f"๐ Python is searching in: {sys.path[0:3]}...")
try:
import special_module
print(f"โ
Success! {special_module.greet()}")
except ImportError as e:
print(f"โ Failed: {e}")
'''
with open('test_import.py', 'w') as f:
f.write(test_script)
# ๐ Run with modified PYTHONPATH
env = os.environ.copy()
env['PYTHONPATH'] = test_dir
result = subprocess.run(
[sys.executable, 'test_import.py'],
env=env,
capture_output=True,
text=True
)
print("๐ Output with PYTHONPATH set:")
print(result.stdout)
# ๐งน Cleanup
os.remove('test_import.py')
# ๐ฎ Run the demonstration
demonstrate_pythonpath()
# ๐ก Pro tip: Setting PYTHONPATH
print("\n๐ก How to set PYTHONPATH:")
print("๐ง Linux/Mac: export PYTHONPATH=/path/to/modules:$PYTHONPATH")
print("๐ช Windows: set PYTHONPATH=C:\\path\\to\\modules;%PYTHONPATH%")
โ ๏ธ Common Pitfalls and Solutions
๐ฑ Pitfall 1: Circular Imports
# โ Wrong way - circular import nightmare!
# file: module_a.py
# from module_b import function_b # ๐ฅ This creates a circle!
# def function_a():
# return function_b()
# file: module_b.py
# from module_a import function_a # ๐ฅ Circle complete!
# def function_b():
# return function_a()
# โ
Correct way - break the circle!
# file: module_a.py
def function_a():
from module_b import function_b # ๐ฏ Import when needed
return function_b()
# file: module_b.py
def function_b():
return "โจ No circular import!"
# ๐ก๏ธ Or restructure your code
# file: shared_functions.py
def shared_function():
return "๐ฏ Shared functionality!"
# Both modules can safely import from shared_functions
๐คฏ Pitfall 2: Name Conflicts
# โ Dangerous - module name conflicts!
# Don't name your file 'math.py' if you need the built-in math module
import os
# ๐ฏ Demonstrate the problem
conflict_code = '''
# math.py - This shadows the built-in math module! ๐ฑ
def sqrt(x):
return "๐ซ This is not the real sqrt!"
'''
# โ
Safe way - use unique names!
safe_code = '''
# my_math_utils.py - Clear, unique name! โจ
import math # Can still use built-in math
def custom_sqrt(x):
"""Our custom square root with emojis! ๐ฏ"""
result = math.sqrt(x)
return f"โ{x} = {result} ๐"
'''
print("๐ Module naming best practices:")
print("โ
Use descriptive, unique names")
print("โ
Avoid built-in module names")
print("โ
Use underscores for multi-word names")
print("โ Don't use: math.py, string.py, sys.py")
print("โ
Do use: my_math.py, string_utils.py, system_helpers.py")
๐ Pitfall 3: Relative Import Confusion
# โ Wrong - confusing relative imports
# from ..parent_module import something # ๐ฅ Can fail in scripts!
# โ
Correct - clear import strategy
print("๐ฆ Package structure for relative imports:")
print("""
my_package/
__init__.py
core/
__init__.py
module_a.py # from . import module_b โ
module_b.py # from ..utils import helper โ
utils/
__init__.py
helper.py
""")
# ๐ฏ Best practice for scripts vs packages
print("\n๐ฏ Import best practices:")
print("๐ For scripts: Use absolute imports")
print("๐ฆ For packages: Use relative imports within the package")
print("๐ For clarity: Always use absolute imports when possible")
๐ ๏ธ Best Practices
- ๐ Organize with Packages: Group related modules in directories with
__init__.py
- ๐ Clear Module Names: Use descriptive names that indicate purpose
- ๐ก๏ธ Avoid Name Conflicts: Never shadow built-in module names
- ๐ฏ Use Virtual Environments: Keep project dependencies isolated
- โจ Document Your Modules: Add docstrings to modules and functions
# ๐ฏ Example of well-organized project
print("""
๐ Best Project Structure:
my_project/
๐ README.md # ๐ Project documentation
๐ requirements.txt # ๐ฆ Dependencies
๐ setup.py # ๐ Package setup
๐ src/ # ๐ป Source code
๐ my_package/
๐ __init__.py
๐ core.py # ๐ฏ Core functionality
๐ utils.py # ๐ ๏ธ Utilities
๐ tests/ # ๐งช Test files
๐ test_core.py
๐ test_utils.py
๐ docs/ # ๐ Documentation
๐ getting_started.md
๐ api_reference.md
""")
๐งช Hands-On Exercise
๐ฏ Challenge: Build a Plugin System
Create a dynamic plugin system that loads modules on demand:
๐ Requirements:
- โ Plugin directory thatโs automatically scanned
- ๐ท๏ธ Each plugin has name, version, and execute() method
- ๐ค Plugin registration system
- ๐ Plugin dependency management
- ๐จ Each plugin has its own emoji identifier!
๐ Bonus Points:
- Add plugin enable/disable functionality
- Implement plugin configuration files
- Create a plugin marketplace simulator
๐ก Solution
๐ Click to see solution
# ๐ฏ Dynamic Plugin System
import os
import json
import importlib.util
from abc import ABC, abstractmethod
class Plugin(ABC):
"""Base plugin class ๐"""
@abstractmethod
def execute(self):
pass
@property
@abstractmethod
def name(self):
pass
@property
@abstractmethod
def version(self):
pass
@property
@abstractmethod
def emoji(self):
pass
class PluginManager:
"""Manage plugins dynamically ๐ฎ"""
def __init__(self, plugin_dir='plugins'):
self.plugin_dir = plugin_dir
self.plugins = {}
self.enabled_plugins = set()
# ๐ Create plugin directory
os.makedirs(plugin_dir, exist_ok=True)
# ๐ Load configuration
self.config_file = os.path.join(plugin_dir, 'config.json')
self.load_config()
print(f"๐ Plugin Manager initialized!")
print(f"๐ Plugin directory: {os.path.abspath(self.plugin_dir)}")
def load_config(self):
"""Load plugin configuration ๐"""
if os.path.exists(self.config_file):
with open(self.config_file, 'r') as f:
config = json.load(f)
self.enabled_plugins = set(config.get('enabled', []))
else:
self.save_config()
def save_config(self):
"""Save plugin configuration ๐พ"""
config = {
'enabled': list(self.enabled_plugins)
}
with open(self.config_file, 'w') as f:
json.dump(config, f, indent=2)
def create_plugin(self, name, code):
"""Create a new plugin file ๐จ"""
filename = f"{name.lower().replace(' ', '_')}_plugin.py"
filepath = os.path.join(self.plugin_dir, filename)
with open(filepath, 'w') as f:
f.write(code)
print(f"โ
Created plugin: {name} ({filename})")
return filename
def discover_plugins(self):
"""Discover all available plugins ๐"""
self.plugins.clear()
for filename in os.listdir(self.plugin_dir):
if filename.endswith('_plugin.py'):
self._load_plugin(filename)
print(f"\n๐ Discovered {len(self.plugins)} plugins!")
return self.plugins
def _load_plugin(self, filename):
"""Load a single plugin ๐ฆ"""
filepath = os.path.join(self.plugin_dir, filename)
plugin_name = filename[:-10] # Remove '_plugin.py'
try:
# ๐ฏ Load the module
spec = importlib.util.spec_from_file_location(
plugin_name, filepath
)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
# ๐ Find Plugin subclasses
for attr_name in dir(module):
attr = getattr(module, attr_name)
if (isinstance(attr, type) and
issubclass(attr, Plugin) and
attr is not Plugin):
plugin_instance = attr()
self.plugins[plugin_name] = plugin_instance
print(f"โ
Loaded: {plugin_instance.emoji} {plugin_instance.name} v{plugin_instance.version}")
break
except Exception as e:
print(f"โ Failed to load {filename}: {e}")
def enable_plugin(self, plugin_name):
"""Enable a plugin ๐ข"""
if plugin_name in self.plugins:
self.enabled_plugins.add(plugin_name)
self.save_config()
print(f"๐ข Enabled: {self.plugins[plugin_name].name}")
else:
print(f"โ Plugin not found: {plugin_name}")
def disable_plugin(self, plugin_name):
"""Disable a plugin ๐ด"""
if plugin_name in self.enabled_plugins:
self.enabled_plugins.remove(plugin_name)
self.save_config()
print(f"๐ด Disabled: {self.plugins[plugin_name].name}")
def execute_plugin(self, plugin_name):
"""Execute a specific plugin ๐"""
if plugin_name not in self.plugins:
print(f"โ Plugin not found: {plugin_name}")
return
if plugin_name not in self.enabled_plugins:
print(f"โ ๏ธ Plugin is disabled: {plugin_name}")
return
plugin = self.plugins[plugin_name]
print(f"\n๐ฏ Executing: {plugin.emoji} {plugin.name}")
return plugin.execute()
def execute_all_enabled(self):
"""Execute all enabled plugins ๐"""
print(f"\n๐ Executing all enabled plugins...")
for plugin_name in self.enabled_plugins:
if plugin_name in self.plugins:
self.execute_plugin(plugin_name)
def list_plugins(self):
"""List all plugins with status ๐"""
print("\n๐ Plugin Status:")
for name, plugin in self.plugins.items():
status = "๐ข Enabled" if name in self.enabled_plugins else "๐ด Disabled"
print(f" {plugin.emoji} {plugin.name} v{plugin.version} - {status}")
# ๐จ Create some example plugins
manager = PluginManager()
# ๐ฏ Plugin 1: Greeting Plugin
greeting_plugin = '''
from plugin_system import Plugin
class GreetingPlugin(Plugin):
@property
def name(self):
return "Greeting Master"
@property
def version(self):
return "1.0.0"
@property
def emoji(self):
return "๐"
def execute(self):
greetings = ["Hello!", "Hi there!", "Greetings!", "Welcome!"]
import random
greeting = random.choice(greetings)
print(f" {self.emoji} {greeting} This is the Greeting Plugin!")
return greeting
'''
# ๐ฒ Plugin 2: Fortune Plugin
fortune_plugin = '''
from plugin_system import Plugin
class FortunePlugin(Plugin):
@property
def name(self):
return "Fortune Teller"
@property
def version(self):
return "2.1.0"
@property
def emoji(self):
return "๐ฎ"
def execute(self):
fortunes = [
"Today brings new opportunities! ๐",
"Your code will run perfectly! ๐ป",
"A bug will reveal itself to you! ๐",
"Documentation will save the day! ๐"
]
import random
fortune = random.choice(fortunes)
print(f" {self.emoji} {fortune}")
return fortune
'''
# ๐ Plugin 3: Stats Plugin
stats_plugin = '''
from plugin_system import Plugin
import datetime
class StatsPlugin(Plugin):
@property
def name(self):
return "System Stats"
@property
def version(self):
return "3.0.5"
@property
def emoji(self):
return "๐"
def execute(self):
stats = {
"time": datetime.datetime.now().strftime("%H:%M:%S"),
"date": datetime.datetime.now().strftime("%Y-%m-%d"),
"python": "3.x"
}
print(f" {self.emoji} Current Stats:")
for key, value in stats.items():
print(f" {key}: {value}")
return stats
'''
# ๐ Create and manage plugins
manager.create_plugin("greeting", greeting_plugin)
manager.create_plugin("fortune", fortune_plugin)
manager.create_plugin("stats", stats_plugin)
# ๐ Discover plugins
manager.discover_plugins()
# ๐ List all plugins
manager.list_plugins()
# ๐ข Enable some plugins
manager.enable_plugin("greeting")
manager.enable_plugin("fortune")
# ๐ Execute all enabled
manager.execute_all_enabled()
# ๐ฏ Execute specific plugin
manager.execute_plugin("stats")
๐ Key Takeaways
Youโve learned so much! Hereโs what you can now do:
- โ Understand Pythonโs module search path with confidence ๐ช
- โ Create and organize packages like a pro ๐ฆ
- โ Debug import errors quickly and effectively ๐
- โ Build modular applications with clean architecture ๐๏ธ
- โ Develop plugin systems and dynamic loaders! ๐
Remember: Good module organization is the foundation of maintainable Python code! ๐ค
๐ค Next Steps
Congratulations! ๐ Youโve mastered Python paths and module search!
Hereโs what to do next:
- ๐ป Practice creating your own package structure
- ๐๏ธ Build a small project with multiple modules
- ๐ Move on to our next tutorial: Python Package Distribution
- ๐ Share your modular projects with the community!
Remember: Every Python expert started by understanding how imports work. Keep organizing, keep modularizing, and most importantly, have fun! ๐
Happy coding! ๐๐โจ