+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Part 174 of 365

๐Ÿ“˜ __name__ == "__main__": Script vs Module

Master __name__ == "__main__": script vs module in Python with practical examples, best practices, and real-world applications ๐Ÿš€

๐Ÿš€Intermediate
25 min read

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โ€™s __name__ == "__main__" pattern! ๐ŸŽ‰ In this guide, weโ€™ll demystify this magical line of code that youโ€™ve probably seen in Python scripts everywhere.

Have you ever wondered why Python scripts often end with this mysterious incantation? ๐Ÿค” Itโ€™s like a secret handshake that tells Python whether your code is the star of the show or just a supporting actor! Whether youโ€™re building command-line tools ๐Ÿ”ง, creating reusable libraries ๐Ÿ“š, or writing test scripts ๐Ÿงช, understanding this pattern is essential for writing professional Python code.

By the end of this tutorial, youโ€™ll know exactly when and why to use this pattern, and youโ€™ll be writing Python modules like a pro! Letโ€™s dive in! ๐ŸŠโ€โ™‚๏ธ

๐Ÿ“š Understanding name == โ€œmainโ€

๐Ÿค” What is name?

Think of __name__ as Pythonโ€™s way of introducing your code to itself! ๐ŸŽญ Itโ€™s like a name tag that changes depending on how your code is being used.

In Python terms, __name__ is a special variable that Python sets automatically:

  • โœจ When you run a file directly: __name__ becomes "__main__"
  • ๐Ÿ“ฆ When you import a file: __name__ becomes the moduleโ€™s name
  • ๐ŸŽฏ This helps Python know what role your code is playing!

๐Ÿ’ก Why Use This Pattern?

Hereโ€™s why developers love this pattern:

  1. Dual Purpose ๐Ÿ”€: Make files work as both scripts AND modules
  2. Clean Imports ๐Ÿ“ฅ: Prevent code from running when imported
  3. Better Testing ๐Ÿงช: Test modules without executing everything
  4. Professional Code ๐Ÿ’ผ: Industry standard practice

Real-world example: Imagine building a calculator ๐Ÿงฎ. With this pattern, you can import the math functions into other programs without the calculatorโ€™s menu popping up every time!

๐Ÿ”ง Basic Syntax and Usage

๐Ÿ“ Simple Example

Letโ€™s start with a friendly example:

# ๐Ÿ‘‹ Hello, Python modules!
print(f"This file's __name__ is: {__name__}")

def greet(name):
    """๐ŸŽ‰ A friendly greeting function"""
    return f"Hello, {name}! Welcome to Python modules! ๐Ÿš€"

def calculate_age(birth_year):
    """๐ŸŽ‚ Calculate age from birth year"""
    from datetime import datetime
    current_year = datetime.now().year
    return current_year - birth_year

# ๐ŸŽฏ The magic line!
if __name__ == "__main__":
    # This code ONLY runs when the file is executed directly
    print("๐Ÿƒ Running as a script!")
    print(greet("Python Learner"))
    age = calculate_age(2000)
    print(f"Someone born in 2000 is {age} years old! ๐ŸŽŠ")

๐Ÿ’ก Explanation: When you run this file directly, youโ€™ll see all the prints. But if you import it into another file, only the functions will be available - no unwanted output!

๐ŸŽฏ Common Patterns

Here are patterns youโ€™ll use daily:

# ๐Ÿ—๏ธ Pattern 1: Script with main function
def main():
    """๐ŸŽฎ Main game loop"""
    print("๐ŸŽฎ Starting the game...")
    # Game logic here
    print("๐Ÿ Game over!")

if __name__ == "__main__":
    main()

# ๐ŸŽจ Pattern 2: Module with test code
def add_numbers(a, b):
    """โž• Add two numbers"""
    return a + b

def multiply_numbers(a, b):
    """โœ–๏ธ Multiply two numbers"""
    return a * b

if __name__ == "__main__":
    # ๐Ÿงช Test our functions
    print(f"2 + 3 = {add_numbers(2, 3)}")
    print(f"4 ร— 5 = {multiply_numbers(4, 5)}")

# ๐Ÿ”„ Pattern 3: Command-line tool
import sys

def process_file(filename):
    """๐Ÿ“„ Process a file"""
    print(f"Processing {filename}... ๐Ÿ”„")
    # File processing logic
    return f"โœ… Processed {filename} successfully!"

if __name__ == "__main__":
    if len(sys.argv) > 1:
        result = process_file(sys.argv[1])
        print(result)
    else:
        print("โš ๏ธ Please provide a filename!")

๐Ÿ’ก Practical Examples

๐Ÿ›’ Example 1: Shopping Cart Module

Letโ€™s build something real:

# ๐Ÿ›๏ธ shopping_cart.py
class Product:
    """๐Ÿ“ฆ A product in our store"""
    def __init__(self, name, price, emoji="๐Ÿ“ฆ"):
        self.name = name
        self.price = price
        self.emoji = emoji
    
    def __str__(self):
        return f"{self.emoji} {self.name} - ${self.price:.2f}"

class ShoppingCart:
    """๐Ÿ›’ Shopping cart for our store"""
    def __init__(self):
        self.items = []
        self.discount = 0
    
    def add_item(self, product, quantity=1):
        """โž• Add item to cart"""
        for _ in range(quantity):
            self.items.append(product)
        print(f"Added {quantity}x {product.emoji} {product.name} to cart! ๐ŸŽ‰")
    
    def calculate_total(self):
        """๐Ÿ’ฐ Calculate total price"""
        subtotal = sum(item.price for item in self.items)
        discount_amount = subtotal * self.discount
        total = subtotal - discount_amount
        return total
    
    def apply_discount(self, percentage):
        """๐Ÿท๏ธ Apply discount"""
        self.discount = percentage / 100
        print(f"Applied {percentage}% discount! ๐ŸŽŠ")
    
    def show_cart(self):
        """๐Ÿ“‹ Display cart contents"""
        if not self.items:
            print("๐Ÿ›’ Your cart is empty!")
            return
        
        print("\n๐Ÿ›’ Shopping Cart:")
        print("-" * 40)
        
        # Group items
        item_counts = {}
        for item in self.items:
            key = f"{item.emoji} {item.name}"
            item_counts[key] = item_counts.get(key, 0) + 1
        
        for item_name, count in item_counts.items():
            price = next(i.price for i in self.items if f"{i.emoji} {i.name}" == item_name)
            print(f"{count}x {item_name} @ ${price:.2f} each")
        
        print("-" * 40)
        print(f"๐Ÿ’ฐ Total: ${self.calculate_total():.2f}")
        if self.discount > 0:
            print(f"๐Ÿท๏ธ Discount: {self.discount * 100}% off!")

# ๐ŸŽฏ Code that runs ONLY when executed directly
if __name__ == "__main__":
    print("๐Ÿช Welcome to Python Shop! ๐ŸŽ‰")
    
    # Create some products
    laptop = Product("Gaming Laptop", 999.99, "๐Ÿ’ป")
    coffee = Product("Premium Coffee", 12.99, "โ˜•")
    book = Product("Python Mastery", 39.99, "๐Ÿ“˜")
    headphones = Product("Wireless Headphones", 149.99, "๐ŸŽง")
    
    # Create cart and shop
    cart = ShoppingCart()
    cart.add_item(laptop)
    cart.add_item(coffee, 3)
    cart.add_item(book)
    cart.add_item(headphones)
    
    # Show cart before discount
    cart.show_cart()
    
    # Apply discount
    print("\n๐ŸŽŠ Special offer time!")
    cart.apply_discount(15)
    cart.show_cart()

๐ŸŽฏ Try it yourself: Import this module in another file and use the classes without the demo shopping session running!

๐ŸŽฎ Example 2: Game Score Tracker

Letโ€™s make it fun:

# ๐Ÿ† game_tracker.py
import json
import os
from datetime import datetime

class Player:
    """๐ŸŽฎ A game player"""
    def __init__(self, name, emoji="๐ŸŽฎ"):
        self.name = name
        self.emoji = emoji
        self.score = 0
        self.level = 1
        self.achievements = []
        self.start_time = datetime.now()
    
    def add_points(self, points):
        """๐ŸŽฏ Add points to player score"""
        self.score += points
        print(f"{self.emoji} {self.name} earned {points} points! โœจ")
        
        # Check for level up
        if self.score >= self.level * 100:
            self.level_up()
    
    def level_up(self):
        """๐Ÿ“ˆ Level up the player"""
        self.level += 1
        achievement = f"๐Ÿ† Level {self.level} Master"
        self.achievements.append(achievement)
        print(f"๐ŸŽ‰ {self.name} reached Level {self.level}! ๐Ÿš€")
        print(f"New achievement: {achievement}")
    
    def get_stats(self):
        """๐Ÿ“Š Get player statistics"""
        play_time = (datetime.now() - self.start_time).seconds // 60
        return {
            "name": self.name,
            "emoji": self.emoji,
            "score": self.score,
            "level": self.level,
            "achievements": self.achievements,
            "play_time_minutes": play_time
        }

class GameSession:
    """๐ŸŽฏ A game session manager"""
    def __init__(self, game_name="Python Quest"):
        self.game_name = game_name
        self.players = {}
        self.high_scores = self.load_high_scores()
    
    def add_player(self, name, emoji="๐ŸŽฎ"):
        """โž• Add a new player"""
        if name not in self.players:
            self.players[name] = Player(name, emoji)
            print(f"Welcome {emoji} {name} to {self.game_name}! ๐ŸŽŠ")
        return self.players[name]
    
    def load_high_scores(self):
        """๐Ÿ“‚ Load high scores from file"""
        if os.path.exists("high_scores.json"):
            with open("high_scores.json", "r") as f:
                return json.load(f)
        return []
    
    def save_high_scores(self):
        """๐Ÿ’พ Save high scores to file"""
        scores = []
        for player in self.players.values():
            scores.append({
                "name": player.name,
                "score": player.score,
                "level": player.level
            })
        
        # Combine with existing scores
        all_scores = scores + self.high_scores
        # Sort by score and keep top 10
        all_scores.sort(key=lambda x: x["score"], reverse=True)
        self.high_scores = all_scores[:10]
        
        with open("high_scores.json", "w") as f:
            json.dump(self.high_scores, f, indent=2)
        print("๐Ÿ’พ High scores saved!")
    
    def show_leaderboard(self):
        """๐Ÿ† Display the leaderboard"""
        print("\n๐Ÿ† LEADERBOARD ๐Ÿ†")
        print("=" * 40)
        for i, score in enumerate(self.high_scores[:5], 1):
            medal = "๐Ÿฅ‡" if i == 1 else "๐Ÿฅˆ" if i == 2 else "๐Ÿฅ‰" if i == 3 else "๐Ÿ…"
            print(f"{medal} {i}. {score['name']} - {score['score']} pts (Lvl {score['level']})")
        print("=" * 40)

def demo_game():
    """๐ŸŽฎ Demo game session"""
    print("๐ŸŽฏ Starting Demo Game Session! ๐ŸŽฏ")
    
    # Create game session
    game = GameSession("Python Adventure")
    
    # Add players
    alice = game.add_player("Alice", "๐Ÿ‘ธ")
    bob = game.add_player("Bob", "๐Ÿค–")
    charlie = game.add_player("Charlie", "๐Ÿฆธ")
    
    # Simulate gameplay
    print("\n๐ŸŽฎ Let the games begin! ๐ŸŽฎ")
    
    # Alice's turn
    alice.add_points(50)
    alice.add_points(75)
    
    # Bob's turn
    bob.add_points(100)
    bob.add_points(25)
    
    # Charlie's turn
    charlie.add_points(60)
    charlie.add_points(80)
    charlie.add_points(40)
    
    # Show final stats
    print("\n๐Ÿ“Š GAME STATS ๐Ÿ“Š")
    for player in game.players.values():
        stats = player.get_stats()
        print(f"\n{stats['emoji']} {stats['name']}:")
        print(f"  ๐ŸŽฏ Score: {stats['score']}")
        print(f"  ๐Ÿ“ˆ Level: {stats['level']}")
        print(f"  ๐Ÿ† Achievements: {len(stats['achievements'])}")
    
    # Save and show leaderboard
    game.save_high_scores()
    game.show_leaderboard()

# ๐ŸŽฏ This only runs when executed directly!
if __name__ == "__main__":
    demo_game()

๐Ÿš€ Advanced Concepts

๐Ÿง™โ€โ™‚๏ธ Advanced Topic 1: Module Testing Framework

When youโ€™re ready to level up, try this advanced pattern:

# ๐Ÿงช test_framework.py
import sys
import traceback
from typing import Callable, Any

class TestRunner:
    """๐Ÿงช A simple test runner"""
    def __init__(self):
        self.tests = []
        self.passed = 0
        self.failed = 0
    
    def test(self, func: Callable) -> Callable:
        """๐ŸŽฏ Decorator to mark test functions"""
        self.tests.append(func)
        return func
    
    def run_tests(self):
        """๐Ÿƒ Run all registered tests"""
        print("๐Ÿงช Running tests...\n")
        
        for test_func in self.tests:
            test_name = test_func.__name__
            try:
                test_func()
                self.passed += 1
                print(f"โœ… {test_name}")
            except AssertionError as e:
                self.failed += 1
                print(f"โŒ {test_name}: {str(e)}")
            except Exception as e:
                self.failed += 1
                print(f"๐Ÿ’ฅ {test_name}: Unexpected error - {str(e)}")
        
        # Summary
        total = self.passed + self.failed
        print(f"\n๐Ÿ“Š Test Results: {self.passed}/{total} passed")
        
        if self.failed == 0:
            print("๐ŸŽ‰ All tests passed! You're awesome! ๐Ÿš€")
        else:
            print(f"โš ๏ธ {self.failed} tests failed. Keep debugging! ๐Ÿ’ช")
        
        return self.failed == 0

# Create global test runner
runner = TestRunner()

# ๐ŸŽจ Example usage
def assert_equal(actual: Any, expected: Any, message: str = ""):
    """โœ… Assert two values are equal"""
    if actual != expected:
        error_msg = f"Expected {expected}, got {actual}"
        if message:
            error_msg = f"{message}: {error_msg}"
        raise AssertionError(error_msg)

@runner.test
def test_addition():
    """โž• Test addition"""
    assert_equal(2 + 2, 4)
    assert_equal(10 + 5, 15)

@runner.test
def test_string_operations():
    """๐Ÿ“ Test string operations"""
    assert_equal("Hello " + "World", "Hello World")
    assert_equal("Python" * 2, "PythonPython")

@runner.test  
def test_list_operations():
    """๐Ÿ“‹ Test list operations"""
    my_list = [1, 2, 3]
    my_list.append(4)
    assert_equal(len(my_list), 4)
    assert_equal(my_list[-1], 4)

# ๐ŸŽฏ Run tests only when executed directly
if __name__ == "__main__":
    success = runner.run_tests()
    sys.exit(0 if success else 1)

๐Ÿ—๏ธ Advanced Topic 2: Plugin System

For the brave developers:

# ๐Ÿ”Œ plugin_system.py
import importlib
import os
from typing import Dict, List, Protocol

class Plugin(Protocol):
    """๐Ÿ”Œ Plugin interface"""
    name: str
    version: str
    
    def initialize(self) -> None:
        """๐Ÿš€ Initialize the plugin"""
        ...
    
    def execute(self, data: Dict) -> Dict:
        """โšก Execute plugin logic"""
        ...

class PluginManager:
    """๐ŸŽฏ Manages plugins"""
    def __init__(self, plugin_dir: str = "plugins"):
        self.plugin_dir = plugin_dir
        self.plugins: Dict[str, Plugin] = {}
    
    def discover_plugins(self):
        """๐Ÿ” Discover and load plugins"""
        if not os.path.exists(self.plugin_dir):
            print(f"โš ๏ธ Plugin directory '{self.plugin_dir}' not found!")
            return
        
        print(f"๐Ÿ” Searching for plugins in {self.plugin_dir}/...")
        
        for filename in os.listdir(self.plugin_dir):
            if filename.endswith(".py") and not filename.startswith("_"):
                module_name = filename[:-3]
                self._load_plugin(module_name)
    
    def _load_plugin(self, module_name: str):
        """๐Ÿ“ฆ Load a single plugin"""
        try:
            module = importlib.import_module(f"{self.plugin_dir}.{module_name}")
            
            # Look for plugin class
            for item_name in dir(module):
                item = getattr(module, item_name)
                if (isinstance(item, type) and 
                    hasattr(item, 'name') and 
                    hasattr(item, 'execute')):
                    plugin = item()
                    self.plugins[plugin.name] = plugin
                    print(f"โœ… Loaded plugin: {plugin.name} v{plugin.version}")
                    plugin.initialize()
                    break
        except Exception as e:
            print(f"โŒ Failed to load {module_name}: {e}")
    
    def execute_plugin(self, plugin_name: str, data: Dict) -> Dict:
        """โšก Execute a specific plugin"""
        if plugin_name in self.plugins:
            return self.plugins[plugin_name].execute(data)
        else:
            print(f"โš ๏ธ Plugin '{plugin_name}' not found!")
            return data
    
    def list_plugins(self):
        """๐Ÿ“‹ List all loaded plugins"""
        if not self.plugins:
            print("๐Ÿ“ญ No plugins loaded!")
        else:
            print("\n๐Ÿ”Œ Available Plugins:")
            for name, plugin in self.plugins.items():
                print(f"  โ€ข {name} (v{plugin.version})")

# ๐ŸŽฏ Demo when run directly
if __name__ == "__main__":
    print("๐Ÿ”Œ Plugin System Demo ๐Ÿ”Œ\n")
    
    # Create plugin manager
    manager = PluginManager()
    
    # Create demo plugin directory
    os.makedirs("plugins", exist_ok=True)
    
    # Create a sample plugin
    sample_plugin = '''
class EmojiPlugin:
    """โœจ Adds emojis to text"""
    name = "emoji_enhancer"
    version = "1.0"
    
    def initialize(self):
        print("โœจ Emoji plugin ready!")
    
    def execute(self, data):
        text = data.get("text", "")
        data["text"] = f"๐ŸŽ‰ {text} ๐Ÿš€"
        return data
'''
    
    with open("plugins/emoji_plugin.py", "w") as f:
        f.write(sample_plugin)
    
    # Load and use plugins
    manager.discover_plugins()
    manager.list_plugins()
    
    # Test plugin
    result = manager.execute_plugin("emoji_enhancer", {"text": "Hello Python"})
    print(f"\n๐Ÿ“ค Result: {result.get('text')}")

โš ๏ธ Common Pitfalls and Solutions

๐Ÿ˜ฑ Pitfall 1: Forgetting the Underscore

# โŒ Wrong way - missing underscores!
if name == "main":  # ๐Ÿ’ฅ This will never be True!
    print("This won't run!")

# โœ… Correct way - double underscores on both sides!
if __name__ == "__main__":  # ๐ŸŽฏ Perfect!
    print("This runs when executed directly! ๐Ÿš€")

๐Ÿคฏ Pitfall 2: Import Side Effects

# โŒ Dangerous - code runs on import!
print("๐Ÿ“ข Loading module...")  # This ALWAYS runs!
database = connect_to_database()  # ๐Ÿ’ฅ Connects every import!
send_email("Module loaded!")  # ๐Ÿ˜ฑ Sends email on import!

# โœ… Safe - control when code runs!
def initialize():
    """๐Ÿš€ Initialize the module"""
    print("๐Ÿ“ข Initializing...")
    return connect_to_database()

if __name__ == "__main__":
    # Only runs when executed directly
    db = initialize()
    print("โœ… Module ready for testing!")

๐Ÿ˜ฐ Pitfall 3: Testing Module Imports

# โŒ Can't test if module imports work
def calculate(x, y):
    return x + y

print(calculate(2, 3))  # Always prints when imported!

# โœ… Better - test code separate from module code
def calculate(x, y):
    """๐Ÿงฎ Calculate sum of two numbers"""
    return x + y

if __name__ == "__main__":
    # Test code here
    print("๐Ÿงช Running tests...")
    assert calculate(2, 3) == 5
    assert calculate(-1, 1) == 0
    print("โœ… All tests passed!")

๐Ÿ› ๏ธ Best Practices

  1. ๐ŸŽฏ Always Use It: Add to every Python file that can be run
  2. ๐Ÿ“ฆ Keep Imports Clean: Donโ€™t execute code at module level
  3. ๐Ÿงช Test Friendly: Put test code under the if statement
  4. ๐Ÿ—๏ธ Use main() Function: Organize executable code in main()
  5. ๐Ÿ“ Document Module Usage: Show how to import AND run

๐Ÿงช Hands-On Exercise

๐ŸŽฏ Challenge: Build a Multi-Purpose Calculator Module

Create a calculator that works both as a module and a standalone program:

๐Ÿ“‹ Requirements:

  • โœ… Basic math operations (add, subtract, multiply, divide)
  • ๐Ÿงฎ Scientific functions (power, square root, factorial)
  • ๐Ÿ“Š Statistics functions (mean, median, mode)
  • ๐ŸŽจ Command-line interface when run directly
  • ๐Ÿ”Œ Clean import for use in other programs
  • ๐ŸŽฏ Each function needs descriptive emoji!

๐Ÿš€ Bonus Points:

  • Add memory feature (store/recall)
  • Implement calculation history
  • Create a simple GUI when run directly

๐Ÿ’ก Solution

๐Ÿ” Click to see solution
# ๐Ÿงฎ calculator.py
import math
import statistics
from typing import List, Union

class Calculator:
    """๐Ÿงฎ A multi-purpose calculator"""
    
    def __init__(self):
        self.memory = 0
        self.history = []
    
    # Basic operations
    def add(self, a: float, b: float) -> float:
        """โž• Add two numbers"""
        result = a + b
        self._record(f"{a} + {b} = {result}")
        return result
    
    def subtract(self, a: float, b: float) -> float:
        """โž– Subtract b from a"""
        result = a - b
        self._record(f"{a} - {b} = {result}")
        return result
    
    def multiply(self, a: float, b: float) -> float:
        """โœ–๏ธ Multiply two numbers"""
        result = a * b
        self._record(f"{a} ร— {b} = {result}")
        return result
    
    def divide(self, a: float, b: float) -> float:
        """โž— Divide a by b"""
        if b == 0:
            raise ValueError("Cannot divide by zero! ๐Ÿšซ")
        result = a / b
        self._record(f"{a} รท {b} = {result}")
        return result
    
    # Scientific operations
    def power(self, base: float, exponent: float) -> float:
        """โšก Calculate base to the power of exponent"""
        result = math.pow(base, exponent)
        self._record(f"{base}^{exponent} = {result}")
        return result
    
    def square_root(self, n: float) -> float:
        """โˆš Calculate square root"""
        if n < 0:
            raise ValueError("Cannot calculate square root of negative number! ๐Ÿšซ")
        result = math.sqrt(n)
        self._record(f"โˆš{n} = {result}")
        return result
    
    def factorial(self, n: int) -> int:
        """โ— Calculate factorial"""
        if n < 0:
            raise ValueError("Factorial is not defined for negative numbers! ๐Ÿšซ")
        result = math.factorial(n)
        self._record(f"{n}! = {result}")
        return result
    
    # Statistics operations
    def mean(self, numbers: List[float]) -> float:
        """๐Ÿ“Š Calculate mean (average)"""
        result = statistics.mean(numbers)
        self._record(f"mean({numbers}) = {result}")
        return result
    
    def median(self, numbers: List[float]) -> float:
        """๐Ÿ“ˆ Calculate median"""
        result = statistics.median(numbers)
        self._record(f"median({numbers}) = {result}")
        return result
    
    def mode(self, numbers: List[float]) -> float:
        """๐Ÿ“‰ Calculate mode (most common)"""
        result = statistics.mode(numbers)
        self._record(f"mode({numbers}) = {result}")
        return result
    
    # Memory operations
    def memory_store(self, value: float):
        """๐Ÿ’พ Store value in memory"""
        self.memory = value
        print(f"๐Ÿ’พ Stored {value} in memory")
    
    def memory_recall(self) -> float:
        """๐Ÿ”„ Recall value from memory"""
        print(f"๐Ÿ”„ Recalled {self.memory} from memory")
        return self.memory
    
    def memory_clear(self):
        """๐Ÿ—‘๏ธ Clear memory"""
        self.memory = 0
        print("๐Ÿ—‘๏ธ Memory cleared")
    
    # History
    def _record(self, operation: str):
        """๐Ÿ“ Record operation in history"""
        self.history.append(operation)
    
    def show_history(self):
        """๐Ÿ“œ Show calculation history"""
        if not self.history:
            print("๐Ÿ“ญ No calculations yet!")
        else:
            print("\n๐Ÿ“œ Calculation History:")
            for i, calc in enumerate(self.history[-10:], 1):
                print(f"  {i}. {calc}")

def interactive_mode():
    """๐ŸŽฎ Interactive calculator mode"""
    calc = Calculator()
    
    print("๐Ÿงฎ Python Calculator ๐Ÿงฎ")
    print("=" * 40)
    print("Commands: +, -, *, /, ^, sqrt, !, mean, median, mode")
    print("Memory: ms (store), mr (recall), mc (clear)")
    print("Other: history, help, quit")
    print("=" * 40)
    
    while True:
        try:
            command = input("\n๐Ÿงฎ Enter command: ").strip().lower()
            
            if command == "quit":
                print("๐Ÿ‘‹ Thanks for calculating! Goodbye! ๐ŸŽ‰")
                break
            elif command == "help":
                print("๐Ÿ“– Enter operations like: 2 + 3, 5 * 4, sqrt 16")
            elif command == "history":
                calc.show_history()
            elif command == "mc":
                calc.memory_clear()
            elif command == "mr":
                print(f"Result: {calc.memory_recall()}")
            elif command.startswith("ms "):
                value = float(command.split()[1])
                calc.memory_store(value)
            elif "+" in command:
                parts = command.split("+")
                result = calc.add(float(parts[0]), float(parts[1]))
                print(f"Result: {result}")
            elif "-" in command and not command.startswith("-"):
                parts = command.split("-")
                result = calc.subtract(float(parts[0]), float(parts[1]))
                print(f"Result: {result}")
            elif "*" in command:
                parts = command.split("*")
                result = calc.multiply(float(parts[0]), float(parts[1]))
                print(f"Result: {result}")
            elif "/" in command:
                parts = command.split("/")
                result = calc.divide(float(parts[0]), float(parts[1]))
                print(f"Result: {result}")
            elif "^" in command:
                parts = command.split("^")
                result = calc.power(float(parts[0]), float(parts[1]))
                print(f"Result: {result}")
            elif command.startswith("sqrt "):
                n = float(command.split()[1])
                result = calc.square_root(n)
                print(f"Result: {result}")
            elif command.endswith("!"):
                n = int(command[:-1])
                result = calc.factorial(n)
                print(f"Result: {result}")
            else:
                print("โ“ Unknown command. Type 'help' for assistance.")
                
        except ValueError as e:
            print(f"โŒ Error: {e}")
        except Exception as e:
            print(f"๐Ÿ’ฅ Unexpected error: {e}")

# ๐ŸŽฏ Run interactive mode only when executed directly
if __name__ == "__main__":
    interactive_mode()

๐ŸŽ“ Key Takeaways

Youโ€™ve learned so much! Hereโ€™s what you can now do:

  • โœ… Understand __name__ and why it changes ๐ŸŽญ
  • โœ… Create dual-purpose files that work as scripts AND modules ๐Ÿ”€
  • โœ… Prevent import side effects in your code ๐Ÿ›ก๏ธ
  • โœ… Write professional Python modules like a pro ๐Ÿ’ผ
  • โœ… Debug module import issues with confidence ๐Ÿ›

Remember: The if __name__ == "__main__": pattern is your friend! It helps you write flexible, reusable Python code. ๐Ÿค

๐Ÿค Next Steps

Congratulations! ๐ŸŽ‰ Youโ€™ve mastered the script vs module pattern!

Hereโ€™s what to do next:

  1. ๐Ÿ’ป Practice with the calculator exercise above
  2. ๐Ÿ—๏ธ Convert your existing scripts to use this pattern
  3. ๐Ÿ“š Move on to our next tutorial: Module Search Path and sys.path
  4. ๐ŸŒŸ Share your dual-purpose modules with others!

Remember: Every Python expert uses this pattern daily. Now youโ€™re one of them! Keep coding, keep learning, and most importantly, have fun! ๐Ÿš€


Happy coding! ๐ŸŽ‰๐Ÿš€โœจ