Interfaces in Python

In the middle of building a web app template with the Tornado web framework I started thinking about how I was including a lot of code dealing with database access in my controller classes. The code is still in a prototype/proof of concept phase but I don’t like egregious cases of mixing concerns so I started thinking about how I could easily swap out providers for my persistence needs.

Now I’m sure I’m not the first person to think of this but I realized that Python makes it really easy to create classes that act like interfaces.

First we will create our class to be used as an interface.

class IPerson:
    def __init__(self, provider_instance):
        self.provider = provider_instance
        self.say_hello = self.provider.say_hello
        self.say_goodbye = self.provider.say_goodbye

We route everything through the provider instance so that the provider can implement helper functions within the class that aren’t necessarily in the interface.

Next we will create two classes that implement the interface.

class Englishman:
    def say_something(self, something):
        return str(something)
    def say_hello(self):
        return self.say_something("Good day to you, sir.")
    def say_goodbye(self):
        return self.say_something("Cheerio!")

class Cowboy:
    def say_hello(self):
        return "Howdy, partner!"
    def say_goodbye(self):
        return "Y'all come back now!"

Now we can say hello and good bye like an Englishman or a Cowboy simply by changing the argument in our interface constructor.

person = IPerson(Englishman())
person.say_hello()  # "Good day to you, sir."
person.say_goodbye()  # "Cheerio!"

person = IPerson(Cowboy())
person.say_hello()  # "Howdy, partner!"
person.say_goodbye()  # "Y'all come back now!"

With this implementation your interface actually enforces something of a contract which surprised me in the flexible world of Python. If a provider doesn’t implement something defined in the interface an AttributeError gets raised and anything not defined in the interface simply isn’t callable. This is essentially the same effect as an abstract base class but it restricts the available attributes/functions to only those defined in the interface removing the temptation to write code downstream with attributes/functions not defined in the contract.

Now I know that Google developed a dependency injection library that allows you to do essentially the same thing. This is essentially a poor man’s dependency injection that doesn’t require you to learn a complex library.

 
0
Kudos
 
0
Kudos

Now read this

The importance of margins

Take a minute and look over the layout of this page. Most importantly I want you to observe what’s on the sides of this text. Assuming you don’t have your browser zoomed in to 400% you should see blank space on either side of this text.... Continue →