### Example involving inheritance: ## The "base" or "super" class: class team: def __init__(self,totalgames): self.wins = 0 self.losses = 0 self.gamesleft = totalgames # constructor def win(self): # method that records a win self.wins += 1 self.gamesleft -= 1 print "yeah!" # win def lose(self): # method that records a loss self.losses += 1 self.gamesleft -=1 print "boo!" # lose def percentage(self): # calculate the team's winning percentage gamesplayed = self.wins + self.losses if gamesplayed==0: return 0 # don't divide by zero! return self.wins/(gamesplayed *1.0) # *1.0 to make it a float # percentage def betterthan(myteam,yourteam): # see if myteam's perentage is better mp = myteam.percentage() yp = yourteam.percentage() return (mp > yp) # returns True or False # betterthan # end class team # Now we can create team objects (instances of class team): nets = team(82) # calls __init__, self = pointer to jets, totalgames = 16 knicks = team(82) knicks.win() # calls win, self = pointer to knicks knicks.win() knicks.lose() nets.lose() nets.lose() nets.lose() #### Now I want teams that can tie. Instead of defining a class from # scratch, I will INHERIT from the team superclass. I will define the # variables and methods necessary to record ties. I will not have to # define methods such as win, lose because they're inherited from the # team class. I will have to OVERRIDE the percentage method, however, # to take into account ties. ##### One other note: knicks.win() is the same as team.win(knicks) # subclass of team class that can tie as well as win/lose: class tieteam(team): def __init__(self,totalgames): team.__init__(self,totalgames) # call superclass constructor self.ties = 0 # subclass constructor ### new methods added by subclass: def tie(self): self.ties += 1 print "snore" # tie ### methods that override superclass methods: def percentage(self): # calculate the team's winning percentage gamesplayed = self.wins + self.losses + self.ties if gamesplayed==0: return 0 # don't divide by zero! # new formula: a tie counts as half a win: return (self.wins + self.ties/2.0)/(gamesplayed *1.0) # percentage # The method 'betterthan' does not need to be redefined: when it calls # 'percentage', it will automatically "dispatch" to the new version of # percentage in the subclass. This feature, called "dynamic dispatch," # is the most important capability of object oriented programming. # It makes the betterthan function **polymorphic**. # class tieteam(team) #### tieteam objects: giants = tieteam(16) giants.lose() giants.win() giants.lose() giants.tie() print "giants' percentage is ", giants.percentage() ################ Another example of inheritance #################### # Superclass 'shape' represents an arbitrary geometric shape: class shape: def __init__(self,x,y): self.x = x self.y = y self.dx = 0 self.dy = 0 # shape def distanceto(self,shape2): # return distance from self to shape2 cx = self.x - shape2.x cy = self.y - shape2.y return (cx*cx + cy*cy)**0.5 # distanceto def setmovement(self,ndx,ndy): self.dx = ndx self.dy = ndy # setmovement def move(self): self.x += self.dx self.y += self.dy # move # we would like to define more functions, but they are not possible # without knowing what kind of precise shape the object represents: def area(self): # return area of geometric shape raise "area of arbitrary shape is undefined" # area # class shape #### subclasses add attributes and methods # circle subclass adds radius class circle(shape): def __init__(self,x,y,radius): shape.__init__(self,x,y) # call superclass constructor self.r = radius # add additional attributes # init def area(self): # returns area of circle: return 3.14 * self.r * self.r # area # detect collision with another circle def collision(self,circle2): d = self.distanceto(circle2) # distanceto function is inherited return d <= (self.r + circle2.r) # collision # class circle # rectangle subclass of shape adds width, height class rectangle(shape): def __init__(self,x,y,width,height): shape.__init__(self,x,y) self.w = width self.h = height # init def area(self): return self.w * self.h # area def collision(self,A): # detect collision with rectangle A cx = abs(self.x - A.x) # abs is absolute value cy = abs(self.y - A.y) if (cx <= self.height+A.height) and (cy <= self.width+A.width): return True else: return False # collision # rectangle ### Question: how can I detect collision between a rectangle and a circle? A = shape(3,4) B = circle(7,8,10) C = rectangle(10,15,5,7) print B.area() print C.area() print A.distanceto(B) ## Point to note: B is a circle, but IT IS ALSO a shape. A subclass (circle) # object can be used where ever a superclass (shape) object is expected, # because a circle IS a shape. But a superclass object cannot be used # in place of a subclass object. Do not confuse "subclass" with "subset". # In set theory, the subset is smaller than the superset. But an instance # of a subclass is LARGER than an instance of the superclass: it contains # everything found in the superclass object plus additional attributes of # its own. ############ Intellectual Traditions of Computer Science: ############ # Why do we call it a "class"? The word originated from the study of # the foundations of mathematics in the early 20th century. The term # "class" is used to distinguish it from "set". A class is a # description of sets. The philosopher/logician Bertrand Russell # noticed that the language of mathematics, if not carefully # structured, can lead to logical paradoxes. If we are allowed to # define a set anyway we like, then we can define a set S as *the set # of all sets that do not contain themselves*. But then does S contain # itself? The answer is both yes and no! This is called "Russell's # Paradox". If such inconsistencies are allowed to exist in the # language of mathematics, then we can't be absolutely sure that 1+1 # is really equal to 2! Russell and others set out to formulate a # purely logical foundation of mathematics that avoids such # inconsistencies. Much of modern computer science is a byproduct of # this movement. In 1940 Alonzo Church formulated the "simple theory # of types" based on ideas in Russell and Whitehead's "Principia # Mathematica". This "type theory" is considered the logical # foundation of computer programming languages. # Anyway, one consequence of all of this is that we need to # distinguish a "class" from a "set". A class *describes* sets. A # subclass is a tighter description than the superclass. If the # superclass describes a self.x and a self.y, and the sublcass also # describes a self.z, then the subclass describes a "smaller" # collection of sets compared to the superclass. But the sets # described by the subclass can be larger than those described by the # superclass.