Claude Artifact

Claude Artifact

Teach me a design pattern with a well established real world use case that is already implemented in python.

I'll explain the Observer pattern, which is widely used in Python and has a concrete implementation in the built-in asyncio library for handling asynchronous events.

from abc import ABC, abstractmethod
from typing import List

# Abstract base classes for the pattern
class Subject(ABC):
    """
    The Subject interface declares common operations for both Stock and other subjects.
    """
    @abstractmethod
    def attach(self, observer) -> None:
        pass

    @abstractmethod
    def detach(self, observer) -> None:
        pass

    @abstractmethod
    def notify(self) -> None:
        pass

class Observer(ABC):
    """
    The Observer interface declares the update method, used by subjects to notify.
    """
    @abstractmethod
    def update(self, subject) -> None:
        pass

# Concrete implementations
class Stock(Subject):
    """
    The Stock maintains a list of observers and sends updates when its price changes.
    """
    def __init__(self, symbol: str, price: float):
        self._observers: List[Observer] = []
        self._symbol = symbol
        self._price = price

    @property
    def price(self) -> float:
        return self._price

    @price.setter
    def price(self, price: float) -> None:
        self._price = price
        self.notify()  # Notify observers when price changes

    def attach(self, observer: Observer) -> None:
        if observer not in self._observers:
            self._observers.append(observer)

    def detach(self, observer: Observer) -> None:
        self._observers.remove(observer)

    def notify(self) -> None:
        for observer in self._observers:
            observer.update(self)

class Trader(Observer):
    """
    Traders react to changes in stock prices they're monitoring.
    """
    def __init__(self, name: str):
        self.name = name

    def update(self, subject: Stock) -> None:
        print(f"Trader {self.name} notified: {subject._symbol} price is now ${subject.price}")

# Example usage
if __name__ == "__main__":
    # Create a stock
    tesla_stock = Stock("TSLA", 180.0)

    # Create traders
    trader1 = Trader("Alice")
    trader2 = Trader("Bob")

    # Traders start watching the stock
    tesla_stock.attach(trader1)
    tesla_stock.attach(trader2)

    # Stock price changes trigger notifications
    tesla_stock.price = 185.0
    tesla_stock.price = 178.5

    # Bob stops watching
    tesla_stock.detach(trader2)

    # Only Alice gets this update
    tesla_stock.price = 190.0

Let me explain why this pattern is important and where it's used in real Python applications:

  1. What is the Observer Pattern?

  2. Real-world Python Implementation: asyncio

    async def handle_data(data):
        print(f"Received: {data}")
    
    # The event loop (subject) observes this coroutine (observer)
    asyncio.create_task(handle_data("example"))
    
    
  3. Other Common Use Cases:

  4. Benefits:

Would you like me to explain any specific part in more detail or show how this pattern is used in one of these real-world frameworks?

Yes answer please

I'll show you how Django, one of Python's most popular web frameworks, implements the Observer pattern through its signals system. This is a real-world application that you can see in action today.

# models.py
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.core.mail import send_mail

class User(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField()
    is_active = models.BooleanField(default=True)

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    bio = models.TextField(blank=True)
    birth_date = models.DateField(null=True)

# signals.py
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    """
    Signal receiver that creates a UserProfile whenever a User is created
    """
    if created:
        UserProfile.objects.create(user=instance)

        # Send welcome email
        send_mail(
            'Welcome to our platform!',
            f'Hi {instance.name}, thanks for joining us!',
            '[email protected]',
            [instance.email],
            fail_silently=False,
        )

# Using signals in practice
def register_new_user():
    # Creating a user automatically triggers the signal
    user = User.objects.create(
        name='John Doe',
        email='[email protected]'
    )
    # At this point:
    # 1. User is created
    # 2. Signal is automatically sent
    # 3. UserProfile is created
    # 4. Welcome email is sent
    return user

# You can also connect multiple receivers
@receiver(post_save, sender=User)
def notify_admin(sender, instance, created, **kwargs):
    """
    Another receiver that notifies admin when new users register
    """
    if created:
        send_mail(
            'New User Registration',
            f'New user registered: {instance.name}',
            '[email protected]',
            ['[email protected]'],
            fail_silently=False,
        )

# In your apps.py, you need to import the signals
from django.apps import AppConfig

class UserConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'users'

    def ready(self):
        # Import signals when the app is ready
        import users.signals

Let me break down how Django uses the Observer pattern:

  1. The Subject (Observable):
  2. The Observers (Receivers):
  3. The Signal:

In the example above: