Menu
Coddy logo textTech

Observer Pattern

Part of the Object Oriented Programming section of Coddy's Python journey — lesson 47 of 64.

The Observer Pattern creates a one-to-many relationship where one object (subject) notifies multiple objects (observers) when its state changes.

Here is a simple Subject class that manages observers:

class Subject:
    def __init__(self):
        self._observers = []
    
    def add_observer(self, observer):
        self._observers.append(observer)
    
    def notify(self, message):
        for observer in self._observers:
            observer.update(message)

The subject keeps a list of observers and can notify them all at once.

Create simple observer classes:

class EmailNotifier:
    def update(self, message):
        print(f"Email sent: {message}")

class SMSNotifier:
    def update(self, message):
        print(f"SMS sent: {message}")

Each observer has an update method that gets called when notified.

Use the observer pattern:

# Create subject
news = Subject()

# Create observers
email = EmailNotifier()
sms = SMSNotifier()

# Add observers to subject
news.add_observer(email)
news.add_observer(sms)

# Notify all observers
news.notify("Breaking news: Python is awesome!")

Create a practical example with a stock price tracker:

class Stock:
    def __init__(self, symbol, price):
        self.symbol = symbol
        self._price = price
        self._observers = []
    
    def add_observer(self, observer):
        self._observers.append(observer)
    
    def set_price(self, price):
        self._price = price
        self.notify()
    
    def notify(self):
        for observer in self._observers:
            observer.update(self.symbol, self._price)

class Investor:
    def __init__(self, name):
        self.name = name
    
    def update(self, symbol, price):
        print(f"{self.name} notified: {symbol} is now ${price}")

# Use the stock tracker
apple_stock = Stock("AAPL", 150)

investor1 = Investor("Alice")
investor2 = Investor("Bob")

apple_stock.add_observer(investor1)
apple_stock.add_observer(investor2)

apple_stock.set_price(155)  # Notifies all investors

Output:

Email sent: Breaking news: Python is awesome!
SMS sent: Breaking news: Python is awesome!
Alice notified: AAPL is now $155
Bob notified: AAPL is now $155

Key Point: The Observer Pattern lets one object notify many others automatically when something changes. The subject maintains a list of observers and calls their update method when needed. This is useful for notifications, event systems, and keeping multiple parts of your application synchronized.

challenge icon

Challenge

Medium

Implement the Observer Pattern by creating a weather monitoring system. You need to create two classes in the designated areas of the code code.

Step 1: Create the WeatherStation class

Write your WeatherStation class where the comment indicates. This class should:

  • Inherit from the Subject class (use class WeatherStation(Subject):)
  • Initialize with:
    • Call the parent constructor using super().__init__()
    • Set initial temperature to 0 using a private attribute self._temperature
  • Implement <strong>set_temperature(self, temperature)</strong>:
    • Update the private temperature attribute
    • Call self.notify(self._temperature) to notify all observers
  • Implement <strong>get_temperature(self)</strong>:
    • Return the current temperature value

Step 2: Create the WeatherDisplay class

Write your WeatherDisplay class where the comment indicates. This class should:

  • Inherit from the Observer class (use class WeatherDisplay(Observer):)
  • Initialize with:
    • Accept a name parameter
    • Store the name as self.name
  • Implement <strong>update(self, temperature)</strong>:
    • Print the temperature update message in the exact format shown below

Message Format:

When a display receives a temperature update, it must print exactly:

Display [name]: Current temperature is [temperature]C

Example Usage:

# Create weather station and displays
station = WeatherStation()
phone_display = WeatherDisplay("Phone")
tablet_display = WeatherDisplay("Tablet")

# Attach displays to station
station.attach(phone_display)
station.attach(tablet_display)

# Update temperature - both displays will be notified
station.set_temperature(25.5)

# Output:
# Display Phone: Current temperature is 25.5C
# Display Tablet: Current temperature is 25.5C

Important Notes:

  • The attach() and detach() methods are already implemented in the Subject base class - you don't need to implement them or call them in your WeatherStation class
  • In the example usage above, station.attach(phone_display) is called by the user of your class, not inside your WeatherStation implementation
  • Your WeatherStation just needs to call self.notify() when the temperature changes - the Subject base class handles the rest
  • Focus on implementing the three required methods in WeatherStation and the two required methods in WeatherDisplay as specified above

Cheat sheet

The Observer Pattern creates a one-to-many relationship where one object (subject) notifies multiple objects (observers) when its state changes.

Basic Subject class that manages observers:

class Subject:
    def __init__(self):
        self._observers = []
    
    def add_observer(self, observer):
        self._observers.append(observer)
    
    def notify(self, message):
        for observer in self._observers:
            observer.update(message)

Observer classes with update method:

class EmailNotifier:
    def update(self, message):
        print(f"Email sent: {message}")

class SMSNotifier:
    def update(self, message):
        print(f"SMS sent: {message}")

Using the observer pattern:

# Create subject
news = Subject()

# Create observers
email = EmailNotifier()
sms = SMSNotifier()

# Add observers to subject
news.add_observer(email)
news.add_observer(sms)

# Notify all observers
news.notify("Breaking news: Python is awesome!")

Practical example with stock price tracker:

class Stock:
    def __init__(self, symbol, price):
        self.symbol = symbol
        self._price = price
        self._observers = []
    
    def add_observer(self, observer):
        self._observers.append(observer)
    
    def set_price(self, price):
        self._price = price
        self.notify()
    
    def notify(self):
        for observer in self._observers:
            observer.update(self.symbol, self._price)

class Investor:
    def __init__(self, name):
        self.name = name
    
    def update(self, symbol, price):
        print(f"{self.name} notified: {symbol} is now ${price}")

The Observer Pattern lets one object notify many others automatically when something changes. The subject maintains a list of observers and calls their update method when needed.

Try it yourself

class Subject:
    def __init__(self):
        self._observers = []
    
    def attach(self, observer):
        self._observers.append(observer)
        
    def detach(self, observer):
        self._observers.remove(observer)
        
    def notify(self, data):
        for observer in self._observers:
            observer.update(data)
            
class Observer:
    def update(self, data):
        pass

# Write your WeatherStation class here

# Write your WeatherDisplay class here

quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming