Skip to content

Instantly share code, notes, and snippets.

@MattOates
Last active Jul 24, 2020
Embed
What would you like to do?
Observer pattern in Python, but has some annoying problems with respect to mypy typing
from typing import Any, Callable, Dict, List, Optional, Set
from abc import ABC, abstractmethod
import logging
LOGGER = logging.getLogger(__name__)
class Observer(ABC):
@abstractmethod
def update(self, observed: "Observable", event: Any) -> None:
pass
class Logger(Observer):
def update(self, observed: "Observable", event: Any) -> None:
if isinstance(observed, "ImplementedThing") and isinstance(event, str):
LOGGER.warning(f"{observed.description} WARNING: {event}")
class Observable(ABC):
_default_observers: Set[Observer] = {Logger()}
_observers: Set[Observer]
def __init__(
self,
using: Optional[List[Observer]] = None
):
self._observers = set()
for observer in Observable._default_observers:
self.subscribe(observer)
if using:
for observer in using:
self.subscribe(observer)
def subscribe(self, observer: Observer) -> None:
self._observers.add(observer)
def unsubscribe(self, observer: Observer) -> None:
self._observers.remove(observer)
def publish(self, event: object) -> None:
for observer in self._observers:
observer.update(self, event)
class ImplementedThing(Observable):
description: str = "Hello World"
def __init__(self, description: str):
super().__init__()
self.description = description
def implement(self):
print(self.description)
self.publish(self.description)
thing = ImplementedThing("Goodbye")
thing.implement()
@MattOates

This comment has been minimized.

Copy link
Owner Author

@MattOates MattOates commented Jul 24, 2020

With the above code we get the error:

observable.py:15: error: Argument 1 of "update" is incompatible with supertype "Observer"; supertype defines the argument type as "Observable"
observable.py:15: note: This violates the Liskov substitution principle
observable.py:15: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
Found 1 error in 1 file (checked 1 source file)

However if you attempt to resolve this its impossible to avoid a This violates the Liskov substitution principle which isn't strictly true as the more general class is an abstract class and can never be instantiated. So there is no substitution here strictly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment