Introduction
Delegation is like passing a job to someone else. In Python, you can do this by using a method called __getattr()__
. It’s almost like asking one object to do a task for another object, just like a subclass asking its parent class for help. Here you can find an article explaining this in more detail.
Implementation in Python
Let’s say we want to create a windowing system. We have a basic window that can open and close. We want to add more features to it, like rotating the window.
To make this happen, we create a WindowsDelegator
class, which helps other classes delegate their work. In our case, we’ll use it with the BasicWindow
class:
class WindowsDelegator:
_delegate: object = None
def __init__(self):
self._delegate = self.get_delegate()
def get_delegate(self) -> object:
raise NotImplementedError
def __getattr__(self, name):
return getattr(self._delegate, name)
Here’s what’s happening:
- We need something to delegate to, called
_delegate
. - In the constructor, we call the
get_delegate()
method to set this attribute. - The
get_delegate()
method is not fully implemented here because it needs to be defined in subclasses. - We define the
__getattr()
method, which tries to find an attribute in the_delegate
object. If it can’t find it, it raises an exception.
Now let’s look at the BasicWindow
class:
class BasicWindow(WindowsDelegator):
_title: str = None
def __init__(self, title: str):
super().__init__()
self._title = title
def open(self):
print(f"Opening window with title: {self._title}")
def close(self):
print(f"Closing window with title: {self._title}")
@property
def title(self) -> str:
return self._title
def get_delegate(self) -> object:
return ExtendedWindow(self)
Here’s what’s happening:
BasicWindow
uses theWindowsDelegator
.- It has a title, open, and close methods.
- The
get_delegate()
method returns an instance of theExtendedWindow
class.
Finally we can implement the ExtendedWindow
class:
class ExtendedWindow:
_window: BasicWindow = None
def __init__(self, window: BasicWindow):
self._window = window
def rotate(self, degrees: int):
print(f"Rotating window with title {self._window.title} by {degrees} degrees")
A summary:
- We embed a
BasicWindow
in this class to be able to access its properties, which we will need as you shall see. - In the constructor we set the appropiate values
- In the
rotate()
method access the title of theBasicWindow
title property to print out a message.
Testing time
The proof is in the pudding, so let’s test it:
if __name__ == "__main__":
w = BasicWindow("My window")
w.open()
w.rotate(45)
w.close()
A summary:
- Create a
BasicWindow
- We open, rotate and close this window. Notice that the call to
rotate()
automatically redirects to the functionality inExtendedWindow
Conclusion
In conclusion, while delegation is possible in Python, it may not always be the most Pythonic way to achieve your goals. It relies on low-level details and can become complex and less readable. If you can find a simpler way to do the same task, that might be a better choice.