In Python, does “favor composition over inheritance” – really apply at all?
Googling best practices for classes in Python for a Django project I kept coming across the phrase “favor composition over inheritance” and the Strategy Design Pattern. First let me quote wikipedia on composition over inheritance:
Composition over inheritance in object-oriented programming is a technique by which classes may achieve polymorphic behavior and code reuse by containing other classes which implement the desired functionality instead of through inheritance.
class AUsefulThing( object ): def __init__( self, aStrategicAlternative ): self.howToDoX = aStrategicAlternative def doX( self, someArg ): self. howToDoX.theAPImethod( someArg, self ) class StrategicAlternative( object ): pass class AlternativeOne( StrategicAlternative ): def theAPIMethod( self, someArg, theUsefulThing ): pass # an implementation class AlternativeTwo( StrategicAlternative ): def theAPImethod( self, someArg, theUsefulThing ): pass # another implementation
Now you can do things like this.
t = AUsefulThing( AlternativeOne() ) t.doX( arg )
S-Lott then provides another Python example pattern that replicates the above with a bit less code.
This had me scratching my head. Not at the example and the helpful response, but at the question itself. Why are we creating functions, then assigning a variable to a class and passing the function in as a parameter? Barooo?
This pattern is practically non-existent in languages that support first class functions. You may want to consider taking advantage of this feature in Python:
def strategy_add(a, b): return a + b def strategy_minus(a, b): return a - b solver = strategy_add print solver(1, 2) solver = strategy_minus print solver(2, 1)
“This approach is very clean and simple.”
I agree with him. I have made the mistake, granted it was out of desperation, of putting a literal in a public property in a class called “objecttype”. This let me pass the object to a function and make decisions on what to do next. Pseudo vbscript-ish code example:
function generate_invoice(object, d) select case(object.objecttype) case "jobs" #do job invoice stuff case "resumes" #do resume stuff here case else
Ok, so it’s not quite as bad as concatenating a string of vbscript and calling the exec(str) method. But it ain’t pretty either. But both got the job done. And in the case of my fake function above, that sure looks like the composition pattern to me. Maybe not exactly, but it’s close. Functions taking classes as parameters and then calling methods within the class in the name of portability. And to reduce code in the classes themselves of course.
I like Christian’s example above a LOT better. Which makes sense because Python has, as noted by bitwise, both First Class Functions and allows for Meta-programming. “Python is not java without the compile” indeed. First Class Functions and Meta Programming used in combination obviate the need for the Strategy design pattern in Python IMHO (see caveats below). And for further support I found this:
“Yes, design patterns are good, but they’re also a sign of weakness in a language.”
The patterns are built in [to Python]. “No one talks about the ‘structured programming’ pattern, or the ‘object-oriented’ pattern, or the ‘function’ pattern anymore.”
- look to features before patterns
- reduce patterns -> shorter code
- needed patterns -> language feature
I’m still a Python newb, but definitely not a programming newb. And So far it looks like you can inherit meta classes with properties to your hearts content to DRY. Yet still, make a thoughtful decision when it comes to how you should implement methods/functions in base classes. Sometimes perhaps a function is better than inheriting a method. Just stop and think. Odds are our fear of inheritance is a learned behavior from being burned by java or another similar lower-level language. I think I need to get over that.
And be thankful that most design patterns are already built into Python. Less code is better.
In closing, and I forget the post I read it on, but just because programming can do ORM (object relational mapping) does NOT mean that a database can. In fact it can’t. And a database deals with the multi-stand-alone class issue by creating a bunch of tables in Django. And one programming matra that I am 100% sure is true is “JOINS are EXPENSIVE.”
Django responds to inherited meta classes by keeping all of the fields in one table, not 20. And perhaps this is me just trying to get over my fear of multi-inheritance and break years of practice. To take advantage of Python being “First Class Everything”. To write code that is Better, faster, stronger than before.