Let's say I have some class, and within instances of that class I want to be able to output certain data to various file types e.g. CSV, SQL, PDF, etc.
The simplest way is just a series of if statements, but that is generally a closed system. Anybody who wants to extend the code has to have control of the class and the ability to modify the existing code.
Here is a really contrived example just to give something a little more concrete:
class Animal:
def __init__(self,species,eats):
self.species = species
self.eats = eats
self.data_outputs {'sql':(server,table), 'csv':path}
def is_carnivorous(self):
self.eats == 'meat'
def is_hippie(self):
self.eats == 'wheatgrass'
def write(self,output_type,data):
output_loc = self.data_outputs[output_type]
if output_type == 'sql':
cursor = connection.cursor()
cursor.execute(some_insert_statement,data)
elif output_type == 'csv':
with open(path,"r") as out:
out.write(data)
If the logic for write
is very involved, maybe delegating to a class to handle the logic could make the method a little bit cleaner:
class Animal:
def __init__(self,species,eats):
self.species = species
self.eats = eats
self.data_outputs {'sql':(server,table), 'csv':path}
def is_carnivorous(self):
self.eats == 'meat'
def is_hippie(self):
self.eats == 'wheatgrass'
def write(self,output_type,data):
output_loc = self.data_outputs[output_type]
if output_type == 'sql':
SQLWriter.write(*output_loc,self.data)
elif output_type == 'csv':
CSVWriter.write(output_loc,data)
class SQLWriter:
def write(self,server,table,data):
cursor = connection.cursor()
cursor.execute(some_insert_statement,data)
class CSVWriter:
def write(self,path,data):
with open(path,"r") as out:
out.write(data)
Either way, both systems are closed, since modifying the write behavior requires subclassing the entire Animal
class just to override write
. It's arguably even worse in the class delegation example because now you've coupled class creation with the write
method so now every time you want to make a new output type you have to both modify the write_data
method ,and make the appropriate class.
Is the pythonic solution to something like this to just use SQLWriter
and CSVWriter
as mixins?:
class Animal(CSVWriter):
def __init__(self,species,eats):
self.species = species
self.eats = eats
def is_carnivorous(self):
self.eats == 'meat'
def is_hippie(self):
self.eats == 'wheatgrass'
This keeps the system open, in that anybody who wants to make a new output type simply needs to write a new mixin and inherit from it, and no existing code needs to be touched to do this. However - the users of Animal
need to be aware that they must inherit from a mixin to get the write
capability, which doesn't seem ideal.
If the write method was dependent on the actual type of class containing the data (Animal
in this example), this would be straightforward in that i'd just have a write
method in that class which any subclassers can override. But in this example I want the write
method to be polymorphic on specific data within the class, not on the class itself.
What is the standard Pythonic (or more generally Object Oriented) solution to this?
EDIT: If you're going to downvote - at least explain what your problem with the question is so I can fix it accordingly.