Reputation: 1039
I am coming from the Java world and I am having a hard time understanding the super() method as it relates to abstract methods.
I have an abstract class with an abstract method. This class' subclasses are responsible for querying my MySQL database and returning formatted reports to me. In half of the subclasses, they use the exact same logic to run the report. In the other half, each needs its own logic. Therefore I want to make run_report
an abstract method.
class Report:
__metaclass__ = ABCMeta
def __init__(self):
self.user = 'root'
self.passwd = ''
self.host = '127.0.0.0.1'
self.port = '80'
self.db = 'animals'
self.conn = mysql.connector.connect(user=self.user, password=self.passd, db=self.db, host=self.host, port=self.port)
self.cursor = self.conn.cursor()
@staticmethod
def construct_query(query, external_data):
finalQuery = query % external_data
return finalQuery
@abstractmethod
def run_report(self, query):
self.cursor.execute(self, query)
results = self.cursor.fetchall()
return data
Here is an example of an implementation of a class that uses the abstract method as is:
class SheepReport(Report):
query = "SELECT COUNT(*) FROM sheep WHERE alive = 1;"
def run_report(query):
super(Report, self).run_report(query)
This syntax seems arcane. My code is too incomplete to test run at the moment, and I'm trying to nip errors in the bud. Am I understanding abstract methods correctly?
By contrast, here is a class that overrides run_report:
class CowReport(Report):
query = "SELECT height, weight FROM cows WHERE name IN (%s);"
def run_report(self):
finalQuery = self.construct_query(query, "'Hilda', 'Gary'");
self.cursor.execute(self, finalQuery)
results = self.cursor.fetchall()
return data
Am I on the right track? All the examples of super() and inheritance I've seen are going over my head, I think I need someone to dumb it down for me.
Upvotes: 1
Views: 3610
Reputation: 7450
First of all, I sincerely hope this is just for learning purposes and not actual production code. Passing unsanitized user input into a query string equals to a full blown SQL injection attack.
With that out of the way...
Abstract classes are usually for defining interfaces, rather than concrete functionality. Nevertherless for what you're trying to do, an abstract class with only query
defined as an abstract property, would simplify considerably your code.
class Report:
__metaclass__ = ABCMeta
def __init__(self):
self.user = 'root'
self.passwd = ''
self.host = '127.0.0.0.1'
self.port = '80'
self.db = 'animals'
self.conn = mysql.connector.connect(user=self.user, password=self.passd, db=self.db,
host=self.host, port=self.port)
self.cursor = self.conn.cursor()
@abstractproperty
def query(self):
return NotImplemented
def construct_query(self, **external_data):
finalQuery = self.query % external_data
return finalQuery
def run_report(self, **external_data):
self.cursor.execute(self, self.construct_query(**external_data))
results = self.cursor.fetchall()
return results
With the above class, then you only need to have a subclass like the below:
class SheepReport(Report):
@property
def query(self):
return "SELECT COUNT(*) FROM sheep WHERE alive = 1;"
Don't mind the unconditional self.query % external_data
. It will work with either template strings or plain strings with empty dictionary data.
Upvotes: 1