I've been coding in Python again in my spare time. I miss Lisp a little, but Python is fun because you get alot for free with the huge module library in the base distribution. I still have a long way to go with on the Lisp learning curve, so I'll be back to it one day.
One of the things that Lisp and Python have in common is that functions are fist class citizens along with classes. That means that you can easily mix and match functional, imperative, and object oriented programming styles. This enables some really expressive and powerful programming experiences.
However, all that flexibility can be a bit confusing to me. I recently struggled with the question of when to use a class and when to just use a function nested in a module. After reading through other people's code, wasting alot of time (and getting nowhere) searching the Internet, and talking to peers, I think I've finally got a handle on it. Even if it's not the answer, I'm going with it.
I believe that most of my Python programming should be OO. OO offers and easy way to separate concerns and map concepts to software. However, there are times when OO seems strained to me. In those cases, I'll use module level functions.
An example that comes readily to mind is persisting objects to a data store. Should your classes have methods that save and load themselves? If they do, then the load method is really strained because it has to populate an instance of the class with data. So, that means you instantiate the object and THEN call load. Doesn't this seem wrong? Shouldn't the instance be instantiated by loading the data?
Perhaps you should make a new class that encapsulates the persistence mechanism for the other class. You could have a data store manager that persists your objects. When the data store manager received a load request, it would instantiate the object with the data from the data store and return it to the requester. This seems cleaner. However, the data store manager class doesn't really encapsulate any instance data. So, it's just a bag of methods. Mmm... strained?
This is an example of where I would use a couple of module level functions. One to store the classes that are part of the module and one to load them. This allows me to separate out a behavior that is not really an object action, but is an action on the object. This makes the solution very clean because, to me, there is much less strain on trying to force object interactions.
Whew! Inner conflict resolved. Breathe out... let the code flow...
9:49:09 AM
|