Online Book Reader

Home Category

Learning Python - Mark Lutz [362]

By Root 1483 0
point behind OOP in general: in OOP, we program by customizing what has already been done, rather than copying or changing existing code. This isn’t always an obvious win to newcomers at first glance, especially given the extra coding requirements of classes. But overall, the programming style implied by classes can cut development time radically compared to other approaches.

For instance, in our example we could theoretically have implemented a custom giveRaise operation without subclassing, but none of the other options yield code as optimal as ours:

Although we could have simply coded Manager from scratch as new, independent code, we would have had to reimplement all the behaviors in Person that are the same for Managers.

Although we could have simply changed the existing Person class in-place for the requirements of Manager’s giveRaise, doing so would probably break the places where we still need the original Person behavior.

Although we could have simply copied the Person class in its entirety, renamed the copy to Manager, and changed its giveRaise, doing so would introduce code redundancy that would double our work in the future—changes made to Person in the future would not be picked up automatically, but would have to be manually propagated to Manager’s code. As usual, the cut-and-paste approach may seem quick now, but it doubles your work in the future.

The customizable hierarchies we can build with classes provide a much better solution for software that will evolve over time. No other tools in Python support this development mode. Because we can tailor and extend our prior work by coding new subclasses, we can leverage what we’ve already done, rather than starting from scratch each time, breaking what already works, or introducing multiple copies of code that may all have to be updated in the future. When done right, OOP is a powerful programmer’s ally.

Step 5: Customizing Constructors, Too

Our code works as it is, but if you study the current version closely, you may be struck by something a bit odd—it seems pointless to have to provide a mgr job name for Manager objects when we create them: this is already implied by the class itself. It would be better if we could somehow fill in this value automatically when a Manager is made.

The trick we need to improve on this turns out to be the same as the one we employed in the prior section: we want to customize the constructor logic for Managers in such a way as to provide a job name automatically. In terms of code, we want to redefine an __init__ method in Manager that provides the mgr string for us. And like with the giveRaise customization, we also want to run the original __init__ in Person by calling through the class name, so it still initializes our objects’ state information attributes.

The following extension will do the job—we’ve coded the new Manager constructor and changed the call that creates tom to not pass in the mgr job name:

# Add customization of constructor in a subclass

class Person:

def __init__(self, name, job=None, pay=0):

self.name = name

self.job = job

self.pay = pay

def lastName(self):

return self.name.split()[-1]

def giveRaise(self, percent):

self.pay = int(self.pay * (1 + percent))

def __str__(self):

return '[Person: %s, %s]' % (self.name, self.pay)

class Manager(Person):

def __init__(self, name, pay): # Redefine constructor

Person.__init__(self, name, 'mgr', pay) # Run original with 'mgr'

def giveRaise(self, percent, bonus=.10):

Person.giveRaise(self, percent + bonus)

if __name__ == '__main__':

bob = Person('Bob Smith')

sue = Person('Sue Jones', job='dev', pay=100000)

print(bob)

print(sue)

print(bob.lastName(), sue.lastName())

sue.giveRaise(.10)

print(sue)

tom = Manager('Tom Jones', 50000) # Job name not needed:

tom.giveRaise(.10) # Implied/set by class

print(tom.lastName())

print(tom)

Again, we’re using the same technique to augment the __init__ constructor here that we used for giveRaise earlier—running the superclass version by calling through the class name directly and passing

Return Main Page Previous Page Next Page

®Online Book Reader