I am creating a query builder class that will help in constructing a query for mongodb from URL params. I have never done much object oriented programming, or designed classes for consumption by people other than myself, besides using basic language constructs and using django's built in Models.
So I have this QueryBuilder
class
class QueryHelper(): """ Help abstract out the problem of querying over vastly different dataschemas. """ def __init__(self, collection_name, field_name, params_dict): self.query_dict = {} self.params_dict = params_dict db = connection.get_db() self.collection = db[collection_name] def _build_query(self): # check params dict and build a mongo query pass
Now in _build_query
I will be checking the params_dict
and populating query_dict
so as to pass it to mongo's find()
function. In doing this I was just wondering if there was an absolute correct approach to as whether _build_query
should return a dictionary or whether it should just modify self.query_dict
. Since it is an internal method I would assume it is OK to just modify self.query_dict
. Is there a right way (pythonic) way of approaching this? Is this just silly and not an important design decision? Any help is appreciated.
Instances as Return Values. Functions and methods can return objects. This is actually nothing new since everything in Python is an object and we have been returning values for quite some time.
Key TakeawaysInstance methods need a class instance and can access the instance through self . Class methods don't need a class instance. They can't access the instance ( self ) but they have access to the class itself via cls .
Class methods cannot access instance variables or instance methods directly—they must use an object reference.
Instance variables hold values that must be referenced by more than one method, constructor or block, or essential parts of an object's state that must be present throughout the class. Instance variables can be declared at the class level before or after use. Access modifiers can be given for instance variables.
It's perfectly fine to modify self.query_dict
as the whole idea of object-oriented programming is that methods can modify an object's state. As long as an object is in a consistent state after a method has finished, you're fine. The fact that _build_query
is an internal method does not matter. You can choose to call _build_query
after in __init__
to construct the query already when the object is created.
The decision mostly matters for testing purposes. For testing purposes, it's convenient to test each method individually without necessarily having to test the whole object's state. But that does not apply in this case because we're talking about an internal method so you alone decide when to call that method, not other objects or other code.
Returning a value is preferable as it allows you to keep all the attribute modifying in one place (__init__
). Also, this makes it easier to extend the code later; suppose you want to override _build_query
in a subclass, then the overriding method can just return a value, without needing to know which attribute to set. Here's an example:
class QueryHelper(object): def __init__(self, param, text): self._param = param self._query = self._build_query(text) def _build_query(self, text): return text + " and ham!" class RefinedQueryHelper(QueryHelper): def _build_query(self, text): # no need to know how the query object is going to be used q = super(RefinedQueryHelper, self)._build_query() return q.replace("ham", "spam")
vs. the "setter version":
class QueryHelper(object): def __init__(self, param, text): self._param = param self._build_query(text) def _build_query(self, text): self._query = text + " and ham!" class RefinedQueryHelper(QueryHelper): def _build_query(self, text): # what if we want to store the query in __query instead? # then we need to modify two classes... super(RefinedQueryHelper, self)._build_query() self._query = self._query.replace("ham", "spam")
If you do choose to set an attribute, you might want to call the method _set_query
for clarity.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With