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 investorsOutput:
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 $155Key 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
MediumImplement 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
- Call the parent constructor using
- 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
nameparameter - Store the name as
self.name
- Accept a
- 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]CExample 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.5CImportant Notes:
- The
attach()anddetach()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
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesIntroduction to OOPClasses vs ObjectsThe self ParameterMethodsAttributesConstructor Method (__init__)Recap - Simple Calculator4Inheritance
Basic InheritanceThe super() FunctionMethod OverridingMultiple InheritanceMethod Resolution OrderRecap - Employee Hierarchy7Special Methods
Magic Methods IntroductionOperator OverloadingContainer Magic MethodsRecap - Custom List10Design Patterns Part 1
Intro to design patternSingleton PatternFactory PatternObserver PatternStrategy Pattern2Decorators
Introduction to DecoratorsProperty DecoratorStatic Method DecoratorClass Method Decorator5Polymorphism
Method Overriding RevisitedDuck TypingAbstract Classes and MethodsInterface DesignRecap - Shape Calculator8Advanced OOP Concepts
Composition vs InheritanceMixinsStatic and Class MethodsClass DecoratorsContext Managers3Class Properties
Instance vs Class VariablesProperty DecoratorsPrivate AttributesRecap - Bank Account Manager6Encapsulation
Public, Protected, Private MemAccess ModifiersInformation HidingProperty Decorators AdvancedRecap - Student Records System12Project: Library Management
Project OverviewBook and User Classes