Jump to content

Archive:Think Python/Inheritance: Difference between revisions

From IdeaWazaWiki
wikademia>Whiteknight
m Think Python: Automatically uploading HTML source of this book from http://www.greenteapress.com/thinkpython/html/. Will convert to wikitext in a separate step
 
wikademia>Wikademia
 
(5 intermediate revisions by 4 users not shown)
Line 1: Line 1:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
{{Think Python/Page}}
            "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML>
<HEAD>


<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
== Chapter&#XA0;18&#XA0;&#XA0;Inheritance ==
<META name="GENERATOR" content="hevea 1.10">
 
<LINK rel="stylesheet" type="text/css" href="book.css">
In this chapter we will develop classes to represent playing cards,
<TITLE>Inheritance</TITLE>
</HEAD>
<BODY >
<A HREF="book018.html"><IMG SRC="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC="contents_motif.gif" ALT="Up"></A>
<A HREF="book020.html"><IMG SRC="next_motif.gif" ALT="Next"></A>
<HR>
<H1 CLASS="chapter"><A NAME="htoc212"><FONT COLOR=black><FONT SIZE=3>Chapter&#XA0;18</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;Inheritance</FONT></FONT></H1><P><FONT COLOR=black><FONT SIZE=3>In this chapter we will develop classes to represent playing cards,
decks of cards, and poker hands. If you don&#X2019;t play poker, you can
decks of cards, and poker hands. If you don&#X2019;t play poker, you can
read about it at </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>wikipedia.org/wiki/Poker</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, but you don&#X2019;t have
read about it at <TT>wikipedia.org/wiki/Poker</TT>, but you don&#X2019;t have
to; I&#X2019;ll tell you what you need to know for the exercises.</FONT></FONT></P><P><A NAME="@default1564"></A><FONT COLOR=black><FONT SIZE=3>
to; I&#X2019;ll tell you what you need to know for the exercises.
</FONT></FONT><A NAME="@default1565"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1566"></A></P><P><FONT COLOR=black><FONT SIZE=3>If you are not familiar with Anglo-American playing cards,
 
you can read about them at </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>wikipedia.org/wiki/Playing_cards</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.</FONT></FONT></P><H2 CLASS="section"><A NAME="toc193"></A><A NAME="htoc213"><FONT COLOR=black><FONT SIZE=3>18.1</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;Card objects</FONT></FONT></H2><P><FONT COLOR=black><FONT SIZE=3>There are fifty-two cards in a deck, each of which belongs to one of
 
 
 
If you are not familiar with Anglo-American playing cards,
you can read about them at <TT>wikipedia.org/wiki/Playing_cards</TT>.
=== 18.1&#XA0;&#XA0;Card objects ===
 
There are fifty-two cards in a deck, each of which belongs to one of
four suits and one of thirteen ranks. The suits are Spades, Hearts,
four suits and one of thirteen ranks. The suits are Spades, Hearts,
Diamonds, and Clubs (in descending order in bridge). The ranks are
Diamonds, and Clubs (in descending order in bridge). The ranks are
Ace, 2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, and King. Depending on
Ace, 2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, and King. Depending on
the game that you are playing, an Ace may be higher than King
the game that you are playing, an Ace may be higher than King
or lower than 2.</FONT></FONT></P><P><A NAME="@default1567"></A><FONT COLOR=black><FONT SIZE=3>
or lower than 2.
</FONT></FONT><A NAME="@default1568"></A></P><P><FONT COLOR=black><FONT SIZE=3>If we want to define a new object to represent a playing card, it is
 
obvious what the attributes should be: </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>rank</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> and
 
</FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>suit</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>. It is not as obvious what type the attributes
 
 
If we want to define a new object to represent a playing card, it is
obvious what the attributes should be: <TT>rank</TT> and
<TT>suit</TT>. It is not as obvious what type the attributes
should be. One possibility is to use strings containing words like
should be. One possibility is to use strings containing words like
</FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>'Spade'</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> for suits and </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>'Queen'</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> for ranks. One problem with
<CODE>'Spade'</CODE> for suits and <CODE>'Queen'</CODE> for ranks. One problem with
this implementation is that it would not be easy to compare cards to
this implementation is that it would not be easy to compare cards to
see which had a higher rank or suit.</FONT></FONT></P><P><A NAME="@default1569"></A><FONT COLOR=black><FONT SIZE=3>
see which had a higher rank or suit.
</FONT></FONT><A NAME="@default1570"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1571"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1572"></A></P><P><FONT COLOR=black><FONT SIZE=3>An alternative is to use integers to </FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>encode</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3> the ranks and suits.
 
 
 
 
An alternative is to use integers to '''encode''' the ranks and suits.
In this context, &#X201C;encode&#X201D; means that we are going to define a mapping
In this context, &#X201C;encode&#X201D; means that we are going to define a mapping
between numbers and suits, or between numbers and ranks. This
between numbers and suits, or between numbers and ranks. This
kind of encoding is not meant to be a secret (that
kind of encoding is not meant to be a secret (that
would be &#X201C;encryption&#X201D;).</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>For example, this table shows the suits and the corresponding integer
would be &#X201C;encryption&#X201D;).
codes:</FONT></FONT></P><TABLE CELLSPACING=6 CELLPADDING=0><TR><TD ALIGN=left NOWRAP><FONT COLOR=black><FONT SIZE=3>Spades</FONT></FONT></TD><TD ALIGN=center NOWRAP><FONT COLOR=black><FONT SIZE=3>&#X21A6;</FONT></FONT></TD><TD ALIGN=left NOWRAP><FONT COLOR=black><FONT SIZE=3>3</FONT></FONT></TD></TR>
 
<TR><TD ALIGN=left NOWRAP><FONT COLOR=black><FONT SIZE=3>Hearts</FONT></FONT></TD><TD ALIGN=center NOWRAP><FONT COLOR=black><FONT SIZE=3>&#X21A6;</FONT></FONT></TD><TD ALIGN=left NOWRAP><FONT COLOR=black><FONT SIZE=3>2</FONT></FONT></TD></TR>
For example, this table shows the suits and the corresponding integer
<TR><TD ALIGN=left NOWRAP><FONT COLOR=black><FONT SIZE=3>Diamonds</FONT></FONT></TD><TD ALIGN=center NOWRAP><FONT COLOR=black><FONT SIZE=3>&#X21A6;</FONT></FONT></TD><TD ALIGN=left NOWRAP><FONT COLOR=black><FONT SIZE=3>1</FONT></FONT></TD></TR>
codes:
<TR><TD ALIGN=left NOWRAP><FONT COLOR=black><FONT SIZE=3>Clubs</FONT></FONT></TD><TD ALIGN=center NOWRAP><FONT COLOR=black><FONT SIZE=3>&#X21A6;</FONT></FONT></TD><TD ALIGN=left NOWRAP><FONT COLOR=black><FONT SIZE=3>0</FONT></FONT></TD></TR>
<TABLE CELLSPACING=6 CELLPADDING=0><TR><TD ALIGN=left NOWRAP>Spades</TD><TD ALIGN=center NOWRAP>&#X21A6;</TD><TD ALIGN=left NOWRAP>3</TD></TR>
</TABLE><P><FONT COLOR=black><FONT SIZE=3>This code makes it easy to compare cards; because higher suits map to
<TR><TD ALIGN=left NOWRAP>Hearts</TD><TD ALIGN=center NOWRAP>&#X21A6;</TD><TD ALIGN=left NOWRAP>2</TD></TR>
higher numbers, we can compare suits by comparing their codes.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>The mapping for ranks is fairly obvious; each of the numerical ranks
<TR><TD ALIGN=left NOWRAP>Diamonds</TD><TD ALIGN=center NOWRAP>&#X21A6;</TD><TD ALIGN=left NOWRAP>1</TD></TR>
maps to the corresponding integer, and for face cards:</FONT></FONT></P><TABLE CELLSPACING=6 CELLPADDING=0><TR><TD ALIGN=left NOWRAP><FONT COLOR=black><FONT SIZE=3>Jack</FONT></FONT></TD><TD ALIGN=center NOWRAP><FONT COLOR=black><FONT SIZE=3>&#X21A6;</FONT></FONT></TD><TD ALIGN=left NOWRAP><FONT COLOR=black><FONT SIZE=3>11</FONT></FONT></TD></TR>
<TR><TD ALIGN=left NOWRAP>Clubs</TD><TD ALIGN=center NOWRAP>&#X21A6;</TD><TD ALIGN=left NOWRAP>0</TD></TR>
<TR><TD ALIGN=left NOWRAP><FONT COLOR=black><FONT SIZE=3>Queen</FONT></FONT></TD><TD ALIGN=center NOWRAP><FONT COLOR=black><FONT SIZE=3>&#X21A6;</FONT></FONT></TD><TD ALIGN=left NOWRAP><FONT COLOR=black><FONT SIZE=3>12</FONT></FONT></TD></TR>
</TABLE>
<TR><TD ALIGN=left NOWRAP><FONT COLOR=black><FONT SIZE=3>King</FONT></FONT></TD><TD ALIGN=center NOWRAP><FONT COLOR=black><FONT SIZE=3>&#X21A6;</FONT></FONT></TD><TD ALIGN=left NOWRAP><FONT COLOR=black><FONT SIZE=3>13</FONT></FONT></TD></TR>
This code makes it easy to compare cards; because higher suits map to
</TABLE><P><FONT COLOR=black><FONT SIZE=3>I am using the </FONT></FONT><FONT COLOR=black><FONT SIZE=3>&#X21A6;</FONT></FONT><FONT COLOR=black><FONT SIZE=3> symbol to make is clear that these mappings
higher numbers, we can compare suits by comparing their codes.
 
The mapping for ranks is fairly obvious; each of the numerical ranks
maps to the corresponding integer, and for face cards:
<TABLE CELLSPACING=6 CELLPADDING=0><TR><TD ALIGN=left NOWRAP>Jack</TD><TD ALIGN=center NOWRAP>&#X21A6;</TD><TD ALIGN=left NOWRAP>11</TD></TR>
<TR><TD ALIGN=left NOWRAP>Queen</TD><TD ALIGN=center NOWRAP>&#X21A6;</TD><TD ALIGN=left NOWRAP>12</TD></TR>
<TR><TD ALIGN=left NOWRAP>King</TD><TD ALIGN=center NOWRAP>&#X21A6;</TD><TD ALIGN=left NOWRAP>13</TD></TR>
</TABLE>
I am using the &#X21A6; symbol to make is clear that these mappings
are not part of the Python program. They are part of the program
are not part of the Python program. They are part of the program
design, but they don&#X2019;t appear explicitly in the code.</FONT></FONT></P><P><A NAME="@default1573"></A><FONT COLOR=black><FONT SIZE=3>
design, but they don&#X2019;t appear explicitly in the code.
</FONT></FONT><A NAME="@default1574"></A></P><P><FONT COLOR=black><FONT SIZE=3>The class definition for </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Card</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> looks like this:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>class Card:
 
 
 
 
The class definition for <TT>Card</TT> looks like this:
<PRE CLASS="verbatim">class Card:
     """represents a standard playing card."""
     """represents a standard playing card."""


Line 58: Line 75:
         self.suit = suit
         self.suit = suit
         self.rank = rank
         self.rank = rank
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>As usual, the init method takes an optional
</PRE>
As usual, the init method takes an optional
parameter for each attribute. The default card is
parameter for each attribute. The default card is
the 2 of Clubs.</FONT></FONT></P><P><A NAME="@default1575"></A><FONT COLOR=black><FONT SIZE=3>
the 2 of Clubs.
</FONT></FONT><A NAME="@default1576"></A></P><P><FONT COLOR=black><FONT SIZE=3>To create a Card, you call </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Card</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> with the
 
suit and rank of the card you want.</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>queen_of_diamonds = Card(1, 12)
 
</FONT></FONT></PRE><H2 CLASS="section"><A NAME="toc194"></A><A NAME="htoc214"><FONT COLOR=black><FONT SIZE=3>18.2</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;Class attributes</FONT></FONT></H2><P><A NAME="@default1577"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1578"></A></P><P><FONT COLOR=black><FONT SIZE=3>In order to print Card objects in a way that people can easily
 
To create a Card, you call <TT>Card</TT> with the
suit and rank of the card you want.
<PRE CLASS="verbatim">queen_of_diamonds = Card(1, 12)
</PRE>
=== 18.2&#XA0;&#XA0;Class attributes ===
 
 
 
In order to print Card objects in a way that people can easily
read, we need a mapping from the integer codes to the corresponding
read, we need a mapping from the integer codes to the corresponding
ranks and suits. A natural way to
ranks and suits. A natural way to
do that is with lists of strings. We assign these lists to </FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>class
do that is with lists of strings. We assign these lists to '''class
attributes</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4># inside class Card:
attributes''':
<PRE CLASS="verbatim"># inside class Card:


     suit_names = ['Clubs', 'Diamonds', 'Hearts', 'Spades']
     suit_names = ['Clubs', 'Diamonds', 'Hearts', 'Spades']
Line 77: Line 105:
         return '%s of %s' % (Card.rank_names[self.rank],
         return '%s of %s' % (Card.rank_names[self.rank],
                             Card.suit_names[self.suit])
                             Card.suit_names[self.suit])
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>Variables like </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>suit_names</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> and </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>rank_names</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>, which are
</PRE>
Variables like <CODE>suit_names</CODE> and <CODE>rank_names</CODE>, which are
defined inside a class but outside of any method, are called
defined inside a class but outside of any method, are called
class attributes because they are associated with the class object  
class attributes because they are associated with the class object  
</FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Card</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.</FONT></FONT></P><P><A NAME="@default1579"></A><FONT COLOR=black><FONT SIZE=3>
<TT>Card</TT>.
</FONT></FONT><A NAME="@default1580"></A></P><P><FONT COLOR=black><FONT SIZE=3>This term distinguished them from variables like </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>suit</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> and </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>rank</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, which are called </FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>instance attributes</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3> because they are
 
associated with a particular instance.</FONT></FONT></P><P><A NAME="@default1581"></A></P><P><FONT COLOR=black><FONT SIZE=3>Both kinds of attribute are accessed using dot notation. For
 
example, in </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>__str__</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>, </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>self</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> is a Card object,
 
and </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>self.rank</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> is its rank. Similarly, </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Card</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>
 
is a class object, and </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>Card.rank_names</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> is a
This term distinguished them from variables like <TT>suit</TT> and <TT>rank</TT>, which are called '''instance attributes''' because they are
list of strings associated with the class.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>Every card has its own </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>suit</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> and </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>rank</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, but there
associated with a particular instance.
is only one copy of </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>suit_names</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> and </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>rank_names</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>Putting it all together, the expression
 
</FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>Card.rank_names[self.rank]</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> means &#X201C;use the attribute </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>rank</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>
Both kinds of attribute are accessed using dot notation. For
from the object </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>self</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> as an index into the list </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>rank_names</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>
example, in <CODE>__str__</CODE>, <TT>self</TT> is a Card object,
from the class </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Card</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, and select the appropriate string.&#X201D;</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>The first element of </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>rank_names</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> is </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>None</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> because there
and <TT>self.rank</TT> is its rank. Similarly, <TT>Card</TT>
is no card with rank zero. By including </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>None</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> as a place-keeper,
is a class object, and <CODE>Card.rank_names</CODE> is a
list of strings associated with the class.
 
Every card has its own <TT>suit</TT> and <TT>rank</TT>, but there
is only one copy of <CODE>suit_names</CODE> and <CODE>rank_names</CODE>.
 
Putting it all together, the expression
<CODE>Card.rank_names[self.rank]</CODE> means &#X201C;use the attribute <TT>rank</TT>
from the object <TT>self</TT> as an index into the list <CODE>rank_names</CODE>
from the class <TT>Card</TT>, and select the appropriate string.&#X201D;
 
The first element of <CODE>rank_names</CODE> is <TT>None</TT> because there
is no card with rank zero. By including <TT>None</TT> as a place-keeper,
we get a mapping with the nice property that the index 2 maps to the
we get a mapping with the nice property that the index 2 maps to the
string </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>'2'</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>, and so on. To avoid this tweak, we could have
string <CODE>'2'</CODE>, and so on. To avoid this tweak, we could have
used a dictionary instead of a list.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>With the methods we have so far, we can create and print cards:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>&gt;&gt;&gt; card1 = Card(2, 11)
used a dictionary instead of a list.
 
With the methods we have so far, we can create and print cards:
<PRE CLASS="verbatim">&gt;&gt;&gt; card1 = Card(2, 11)
&gt;&gt;&gt; print card1
&gt;&gt;&gt; print card1
Jack of Hearts
Jack of Hearts
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>Here is a diagram that shows the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Card</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> class object
</PRE>
and one Card instance:</FONT></FONT></P><P><A NAME="@default1582"></A><FONT COLOR=black><FONT SIZE=3>
Here is a diagram that shows the <TT>Card</TT> class object
</FONT></FONT><A NAME="@default1583"></A><FONT COLOR=black><FONT SIZE=3>
and one Card instance:
</FONT></FONT><A NAME="@default1584"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1585"></A></P><DIV CLASS="center"><FONT COLOR=black><FONT SIZE=3><IMG SRC="book026.png"></FONT></FONT></DIV><P><FONT COLOR=black><FONT SIZE=3><TT>Card</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> is a class object, so it has type </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>type</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>. </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>card1</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> has type </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Card</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>. (To save space, I didn&#X2019;t draw the
 
contents of </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>suit_names</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> and </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>rank_names</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>).</FONT></FONT></P><H2 CLASS="section"><A NAME="toc195"></A><A NAME="htoc215"><FONT COLOR=black><FONT SIZE=3>18.3</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;Comparing cards</FONT></FONT></H2><P><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="comparecard"></A></P><P><A NAME="@default1586"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1587"></A></P><P><FONT COLOR=black><FONT SIZE=3>For built-in types, there are conditional operators
 
(</FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>&lt;</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>&gt;</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>==</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, etc.)
<DIV CLASS="center"><IMG SRC="book026.png"></DIV>
<TT>Card</TT> is a class object, so it has type <TT>type</TT>. <TT>card1</TT> has type <TT>Card</TT>. (To save space, I didn&#X2019;t draw the
contents of <CODE>suit_names</CODE> and <CODE>rank_names</CODE>).
 
=== 18.3&#XA0;&#XA0;Comparing cards ===
 
 
 
 
 
 
 
For built-in types, there are conditional operators
(<TT>&lt;</TT>, <TT>&gt;</TT>, <TT>==</TT>, etc.)
that compare
that compare
values and determine when one is greater than, less than, or equal to
values and determine when one is greater than, less than, or equal to
another. For user-defined types, we can override the behavior of
another. For user-defined types, we can override the behavior of
the built-in operators by providing a method named
the built-in operators by providing a method named
</FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>__cmp__</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>. </FONT></FONT></P><P><CODE><FONT COLOR=black><FONT SIZE=3>__cmp__</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> takes two parameters, </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>self</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> and </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>other</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>,
<CODE>__cmp__</CODE>.  
 
<CODE>__cmp__</CODE> takes two parameters, <TT>self</TT> and <TT>other</TT>,
and returns a positive number if the first object is greater, a
and returns a positive number if the first object is greater, a
negative number if the second object is greater, and 0 if they are
negative number if the second object is greater, and 0 if they are
equal to each other.</FONT></FONT></P><P><A NAME="@default1588"></A><FONT COLOR=black><FONT SIZE=3>
equal to each other.
</FONT></FONT><A NAME="@default1589"></A></P><P><FONT COLOR=black><FONT SIZE=3>The correct ordering for cards is not obvious.
 
 
 
 
The correct ordering for cards is not obvious.
For example, which
For example, which
is better, the 3 of Clubs or the 2 of Diamonds? One has a higher
is better, the 3 of Clubs or the 2 of Diamonds? One has a higher
rank, but the other has a higher suit. In order to compare
rank, but the other has a higher suit. In order to compare
cards, you have to decide whether rank or suit is more important.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>The answer might depend on what game you are playing, but to keep
cards, you have to decide whether rank or suit is more important.
 
The answer might depend on what game you are playing, but to keep
things simple, we&#X2019;ll make the arbitrary choice that suit is more
things simple, we&#X2019;ll make the arbitrary choice that suit is more
important, so all of the Spades outrank all of the Diamonds,
important, so all of the Spades outrank all of the Diamonds,
and so on.</FONT></FONT></P><P><A NAME="@default1590"></A><FONT COLOR=black><FONT SIZE=3>
and so on.
</FONT></FONT><A NAME="@default1591"></A></P><P><FONT COLOR=black><FONT SIZE=3>With that decided, we can write </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>__cmp__</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4># inside class Card:
 
 
 
 
With that decided, we can write <CODE>__cmp__</CODE>:
<PRE CLASS="verbatim"># inside class Card:


     def __cmp__(self, other):
     def __cmp__(self, other):
Line 135: Line 205:
         # ranks are the same... it's a tie
         # ranks are the same... it's a tie
         return 0     
         return 0     
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>You can write this more concisely using tuple comparison:</FONT></FONT></P><P><A NAME="@default1592"></A><FONT COLOR=black><FONT SIZE=3>
</PRE>
</FONT></FONT><A NAME="@default1593"></A></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4># inside class Card:
You can write this more concisely using tuple comparison:
 
 
 
<PRE CLASS="verbatim"># inside class Card:


     def __cmp__(self, other):
     def __cmp__(self, other):
Line 142: Line 216:
         t2 = other.suit, other.rank
         t2 = other.suit, other.rank
         return cmp(t1, t2)
         return cmp(t1, t2)
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>The built-in function </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>cmp</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> has the same interface as
</PRE>
the method </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>__cmp__</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>: it takes two values and returns
The built-in function <TT>cmp</TT> has the same interface as
the method <CODE>__cmp__</CODE>: it takes two values and returns
a positive number if the first is larger, a negative number
a positive number if the first is larger, a negative number
of the second is larger, and 0 if they are equal.</FONT></FONT></P><P><A NAME="@default1594"></A><FONT COLOR=black><FONT SIZE=3>
of the second is larger, and 0 if they are equal.
</FONT></FONT><A NAME="@default1595"></A></P><DIV CLASS="theorem"><FONT COLOR=black><FONT SIZE=3><B>Exercise&#XA0;1</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;<EM>
 
Write a </EM></FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3><EM>__cmp__</EM></FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3><EM> method for Time objects. Hint: you
 
 
<DIV CLASS="theorem">'''Exercise&#XA0;1'''&#XA0;&#XA0;''
Write a ''<CODE>''__cmp__''</CODE>'' method for Time objects. Hint: you
can use tuple comparison, but you also might consider using
can use tuple comparison, but you also might consider using
integer subtraction.</EM></FONT></FONT></DIV><H2 CLASS="section"><A NAME="toc196"></A><A NAME="htoc216"><FONT COLOR=black><FONT SIZE=3>18.4</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;Decks</FONT></FONT></H2><P><FONT COLOR=black><FONT SIZE=3>
integer subtraction.''</DIV>
</FONT></FONT><A NAME="@default1596"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1597"></A></P><P><FONT COLOR=black><FONT SIZE=3>Now that we have Cards, the next step is to define Decks. Since a
=== 18.4&#XA0;&#XA0;Decks ===
 
 
 
Now that we have Cards, the next step is to define Decks. Since a
deck is made up of cards, it is natural for each Deck to contain a
deck is made up of cards, it is natural for each Deck to contain a
list of cards as an attribute.</FONT></FONT></P><P><A NAME="@default1598"></A><FONT COLOR=black><FONT SIZE=3>
list of cards as an attribute.
</FONT></FONT><A NAME="@default1599"></A></P><P><FONT COLOR=black><FONT SIZE=3>The following is a class definition for </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Deck</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>. The
 
init method creates the attribute </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>cards</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> and generates
 
the standard set of fifty-two cards:</FONT></FONT></P><P><A NAME="@default1600"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1601"></A></P><P><A NAME="@default1602"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1603"></A></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>class Deck:
The following is a class definition for <TT>Deck</TT>. The
init method creates the attribute <TT>cards</TT> and generates
the standard set of fifty-two cards:
 
 
 
 
 
 
<PRE CLASS="verbatim">class Deck:


     def __init__(self):
     def __init__(self):
Line 166: Line 257:
                 card = Card(suit, rank)
                 card = Card(suit, rank)
                 self.cards.append(card)
                 self.cards.append(card)
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>The easiest way to populate the deck is with a nested loop. The outer
</PRE>
The easiest way to populate the deck is with a nested loop. The outer
loop enumerates the suits from 0 to 3. The inner loop enumerates the
loop enumerates the suits from 0 to 3. The inner loop enumerates the
ranks from 1 to 13. Each iteration
ranks from 1 to 13. Each iteration
creates a new Card with the current suit and rank,
creates a new Card with the current suit and rank,
and appends it to </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>self.cards</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.</FONT></FONT></P><P><A NAME="@default1604"></A><FONT COLOR=black><FONT SIZE=3>
and appends it to <TT>self.cards</TT>.
</FONT></FONT><A NAME="@default1605"></A></P><H2 CLASS="section"><A NAME="toc197"></A><A NAME="htoc217"><FONT COLOR=black><FONT SIZE=3>18.5</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;Printing the deck</FONT></FONT></H2><P><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="printdeck"></A></P><P><A NAME="@default1606"></A><FONT COLOR=black><FONT SIZE=3>
=== 18.5&#XA0;&#XA0;Printing the deck ===
</FONT></FONT><A NAME="@default1607"></A></P><P><FONT COLOR=black><FONT SIZE=3>Here is a </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>__str__</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> method for </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Deck</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>#inside class Deck:
 
 
 
 
 
 
 
Here is a <CODE>__str__</CODE> method for <TT>Deck</TT>:
<PRE CLASS="verbatim">#inside class Deck:


     def __str__(self):
     def __str__(self):
Line 180: Line 280:
             res.append(str(card))
             res.append(str(card))
         return '\n'.join(res)
         return '\n'.join(res)
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>This method demonstrates an efficient way to accumulate a large
</PRE>
string: building a list of strings and then using </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>join</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.
This method demonstrates an efficient way to accumulate a large
The built-in function </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>str</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> invokes the </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>__str__</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>
string: building a list of strings and then using <TT>join</TT>.
method on each card and returns the string representation.</FONT></FONT></P><P><A NAME="@default1608"></A><FONT COLOR=black><FONT SIZE=3>
The built-in function <TT>str</TT> invokes the <CODE>__str__</CODE>
</FONT></FONT><A NAME="@default1609"></A><FONT COLOR=black><FONT SIZE=3>
method on each card and returns the string representation.
</FONT></FONT><A NAME="@default1610"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1611"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1612"></A></P><P><FONT COLOR=black><FONT SIZE=3>Since we invoke </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>join</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> on a newline character, the cards
 
are separated by newlines. Here&#X2019;s what the result looks like:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>&gt;&gt;&gt; deck = Deck()
 
 
 
 
Since we invoke <TT>join</TT> on a newline character, the cards
are separated by newlines. Here&#X2019;s what the result looks like:
<PRE CLASS="verbatim">&gt;&gt;&gt; deck = Deck()
&gt;&gt;&gt; print deck
&gt;&gt;&gt; print deck
Ace of Clubs
Ace of Clubs
Line 198: Line 304:
Queen of Spades
Queen of Spades
King of Spades
King of Spades
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>Even though the result appears on 52 lines, it is
</PRE>
one long string that contains newlines.</FONT></FONT></P><H2 CLASS="section"><A NAME="toc198"></A><A NAME="htoc218"><FONT COLOR=black><FONT SIZE=3>18.6</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;Add, remove, shuffle and sort</FONT></FONT></H2><P><FONT COLOR=black><FONT SIZE=3>To deal cards, we would like a method that
Even though the result appears on 52 lines, it is
one long string that contains newlines.
=== 18.6&#XA0;&#XA0;Add, remove, shuffle and sort ===
 
To deal cards, we would like a method that
removes a card from the deck and returns it.
removes a card from the deck and returns it.
The list method </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>pop</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> provides a convenient way to do that:</FONT></FONT></P><P><A NAME="@default1613"></A><FONT COLOR=black><FONT SIZE=3>
The list method <TT>pop</TT> provides a convenient way to do that:
</FONT></FONT><A NAME="@default1614"></A></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>#inside class Deck:
 
 
 
<PRE CLASS="verbatim">#inside class Deck:


     def pop_card(self):
     def pop_card(self):
         return self.cards.pop()
         return self.cards.pop()
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>Since </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>pop</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> removes the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>last</EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3> card in the list, we are
</PRE>
Since <TT>pop</TT> removes the ''last'' card in the list, we are
dealing from the bottom of the deck. In real life bottom dealing is
dealing from the bottom of the deck. In real life bottom dealing is
frowned upon</FONT></FONT><SUP><A NAME="text30" HREF="#note30"><FONT COLOR=black><FONT SIZE=3>1</FONT></FONT></A></SUP><FONT COLOR=black><FONT SIZE=3>,
frowned upon<SUP>1</SUP>,
but in this context it&#X2019;s ok.</FONT></FONT></P><P><A NAME="@default1615"></A><FONT COLOR=black><FONT SIZE=3>
but in this context it&#X2019;s ok.
</FONT></FONT><A NAME="@default1616"></A></P><P><FONT COLOR=black><FONT SIZE=3>To add a card, we can use the list method </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>append</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>#inside class Deck:
 
 
 
 
To add a card, we can use the list method <TT>append</TT>:
<PRE CLASS="verbatim">#inside class Deck:


     def add_card(self, card):
     def add_card(self, card):
         self.cards.append(card)
         self.cards.append(card)
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>A method like this that uses another function without doing
</PRE>
much real work is sometimes called a </FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>veneer</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>. The metaphor
A method like this that uses another function without doing
much real work is sometimes called a '''veneer'''. The metaphor
comes from woodworking, where it is common to glue a thin
comes from woodworking, where it is common to glue a thin
layer of good quality wood to the surface of a cheaper piece of
layer of good quality wood to the surface of a cheaper piece of
wood.</FONT></FONT></P><P><A NAME="@default1617"></A></P><P><FONT COLOR=black><FONT SIZE=3>In this case we are defining a &#X201C;thin&#X201D; method that expresses
wood.
a list operation in terms that are appropriate for decks.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>As another example, we can write a Deck method named </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>shuffle</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>
 
using the function </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>shuffle</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> from the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>random</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> module:</FONT></FONT></P><P><A NAME="@default1618"></A><FONT COLOR=black><FONT SIZE=3>
In this case we are defining a &#X201C;thin&#X201D; method that expresses
</FONT></FONT><A NAME="@default1619"></A><FONT COLOR=black><FONT SIZE=3>
a list operation in terms that are appropriate for decks.
</FONT></FONT><A NAME="@default1620"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1621"></A></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4># inside class Deck:
As another example, we can write a Deck method named <TT>shuffle</TT>
using the function <TT>shuffle</TT> from the <TT>random</TT> module:
 
 
 
 
 
<PRE CLASS="verbatim"># inside class Deck:
              
              
     def shuffle(self):
     def shuffle(self):
         random.shuffle(self.cards)
         random.shuffle(self.cards)
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>Don&#X2019;t forget to import </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>random</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.</FONT></FONT></P><DIV CLASS="theorem"><FONT COLOR=black><FONT SIZE=3><B>Exercise&#XA0;2</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;<EM>
</PRE>
</EM></FONT></FONT><A NAME="@default1622"></A><FONT COLOR=black><FONT SIZE=3><EM>
Don&#X2019;t forget to import <TT>random</TT>.
</EM></FONT></FONT><A NAME="@default1623"></A><P><FONT COLOR=black><FONT SIZE=3><EM>Write a Deck method named </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>sort</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> that uses the list method
<DIV CLASS="theorem">'''Exercise&#XA0;2'''&#XA0;&#XA0;''
</EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>sort</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> to sort the cards in a </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>Deck</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>. </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>sort</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> uses
''''
the </EM></FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3><EM>__cmp__</EM></FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3><EM> method we defined to determine sort order.
''
</EM></FONT></FONT></P></DIV><H2 CLASS="section"><A NAME="toc199"></A><A NAME="htoc219"><FONT COLOR=black><FONT SIZE=3>18.7</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;Inheritance</FONT></FONT></H2><P><A NAME="@default1624"></A><FONT COLOR=black><FONT SIZE=3>
''Write a Deck method named ''''<TT>sort</TT>'''' that uses the list method
</FONT></FONT><A NAME="@default1625"></A></P><P><FONT COLOR=black><FONT SIZE=3>The language feature most often associated with object-oriented
''''<TT>sort</TT>'''' to sort the cards in a ''''<TT>Deck</TT>''''. ''''<TT>sort</TT>'''' uses
programming is </FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>inheritance</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>. Inheritance is the ability to
the ''<CODE>''__cmp__''</CODE>'' method we defined to determine sort order.
''
</DIV>
=== 18.7&#XA0;&#XA0;Inheritance ===
 
 
 
 
The language feature most often associated with object-oriented
programming is '''inheritance'''. Inheritance is the ability to
define a new class that is a modified version of an existing
define a new class that is a modified version of an existing
class.</FONT></FONT></P><P><A NAME="@default1626"></A><FONT COLOR=black><FONT SIZE=3>
class.
</FONT></FONT><A NAME="@default1627"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1628"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1629"></A></P><P><FONT COLOR=black><FONT SIZE=3>It is called &#X201C;inheritance&#X201D; because the new class inherits the
 
 
 
 
It is called &#X201C;inheritance&#X201D; because the new class inherits the
methods of the existing class. Extending this metaphor, the existing
methods of the existing class. Extending this metaphor, the existing
class is called the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>parent</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3> and the new class is
class is called the '''parent''' and the new class is
called the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>child</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>As an example, let&#X2019;s say we want a class to represent a &#X201C;hand,&#X201D;
called the '''child'''.
 
As an example, let&#X2019;s say we want a class to represent a &#X201C;hand,&#X201D;
that is, the set of cards held by one player. A hand is similar to a
that is, the set of cards held by one player. A hand is similar to a
deck: both are made up of a set of cards, and both require operations
deck: both are made up of a set of cards, and both require operations
like adding and removing cards.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>A hand is also different from a deck; there are operations we want for
like adding and removing cards.
 
A hand is also different from a deck; there are operations we want for
hands that don&#X2019;t make sense for a deck. For example, in poker we
hands that don&#X2019;t make sense for a deck. For example, in poker we
might compare two hands to see which one wins. In bridge, we might
might compare two hands to see which one wins. In bridge, we might
compute a score for a hand in order to make a bid.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>This relationship between classes&#X2014;similar, but different&#X2014;lends
compute a score for a hand in order to make a bid.
itself to inheritance. </FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>The definition of a child class is like other class definitions,
 
but the name of the parent class appears in parentheses:</FONT></FONT></P><P><A NAME="@default1630"></A><FONT COLOR=black><FONT SIZE=3>
This relationship between classes&#X2014;similar, but different&#X2014;lends
</FONT></FONT><A NAME="@default1631"></A><FONT COLOR=black><FONT SIZE=3>
itself to inheritance.  
</FONT></FONT><A NAME="@default1632"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1633"></A><FONT COLOR=black><FONT SIZE=3>
The definition of a child class is like other class definitions,
</FONT></FONT><A NAME="@default1634"></A></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>class Hand(Deck):
but the name of the parent class appears in parentheses:
 
 
 
 
 
 
<PRE CLASS="verbatim">class Hand(Deck):
     """represents a hand of playing cards"""
     """represents a hand of playing cards"""
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>This definition indicates that </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Hand</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> inherits from </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Deck</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>;
</PRE>
that means we can use methods like </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>pop_card</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> and </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>add_card</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>
This definition indicates that <TT>Hand</TT> inherits from <TT>Deck</TT>;
for Hands as well as Decks.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3><TT>Hand</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> also inherits </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>__init__</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> from </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Deck</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, but
that means we can use methods like <CODE>pop_card</CODE> and <CODE>add_card</CODE>
for Hands as well as Decks.
 
<TT>Hand</TT> also inherits <CODE>__init__</CODE> from <TT>Deck</TT>, but
it doesn&#X2019;t really do what we want: instead of populating the hand
it doesn&#X2019;t really do what we want: instead of populating the hand
with 52 new cards, the init method for Hands should initialize
with 52 new cards, the init method for Hands should initialize
</FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>cards</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> with an empty list.</FONT></FONT></P><P><A NAME="@default1635"></A><FONT COLOR=black><FONT SIZE=3>
<TT>cards</TT> with an empty list.
</FONT></FONT><A NAME="@default1636"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1637"></A></P><P><FONT COLOR=black><FONT SIZE=3>If we provide an init method in the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Hand</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> class, it overrides the
 
one in the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Deck</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> class:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4># inside class Hand:
 
 
 
If we provide an init method in the <TT>Hand</TT> class, it overrides the
one in the <TT>Deck</TT> class:
<PRE CLASS="verbatim"># inside class Hand:


     def __init__(self, label=''):
     def __init__(self, label=''):
         self.cards = []
         self.cards = []
         self.label = label
         self.label = label
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>So when you create a Hand, Python invokes this init method:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>&gt;&gt;&gt; hand = Hand('new hand')
</PRE>
So when you create a Hand, Python invokes this init method:
<PRE CLASS="verbatim">&gt;&gt;&gt; hand = Hand('new hand')
&gt;&gt;&gt; print hand.cards
&gt;&gt;&gt; print hand.cards
[]
[]
&gt;&gt;&gt; print hand.label
&gt;&gt;&gt; print hand.label
new hand
new hand
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>But the other methods are inherited from </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Deck</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, so we can use
</PRE>
</FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>pop_card</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> and </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>add_card</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> to deal a card:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>&gt;&gt;&gt; deck = Deck()
But the other methods are inherited from <TT>Deck</TT>, so we can use
<CODE>pop_card</CODE> and <CODE>add_card</CODE> to deal a card:
<PRE CLASS="verbatim">&gt;&gt;&gt; deck = Deck()
&gt;&gt;&gt; card = deck.pop_card()
&gt;&gt;&gt; card = deck.pop_card()
&gt;&gt;&gt; hand.add_card(card)
&gt;&gt;&gt; hand.add_card(card)
&gt;&gt;&gt; print hand
&gt;&gt;&gt; print hand
King of Spades
King of Spades
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>A natural next step is to encapsulate this code in a method
</PRE>
called </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>move_cards</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>:</FONT></FONT></P><P><A NAME="@default1638"></A></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>#inside class Deck:
A natural next step is to encapsulate this code in a method
called <CODE>move_cards</CODE>:
 
<PRE CLASS="verbatim">#inside class Deck:


     def move_cards(self, hand, num):
     def move_cards(self, hand, num):
         for i in range(num):
         for i in range(num):
             hand.add_card(self.pop_card())
             hand.add_card(self.pop_card())
</FONT></FONT></PRE><P><CODE><FONT COLOR=black><FONT SIZE=3>move_cards</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> takes two arguments, a Hand object and the number of
</PRE>
cards to deal. It modifies both </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>self</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> and </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>hand</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, and
<CODE>move_cards</CODE> takes two arguments, a Hand object and the number of
returns </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>None</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>In some games, cards are moved from one hand to another,
cards to deal. It modifies both <TT>self</TT> and <TT>hand</TT>, and
or from a hand back to the deck. You can use </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>move_cards</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>
returns <TT>None</TT>.
for any of these operations: </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>self</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> can be either a Deck
 
or a Hand, and </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>hand</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, despite the name, can also be a </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Deck</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.</FONT></FONT></P><DIV CLASS="theorem"><FONT COLOR=black><FONT SIZE=3><B>Exercise&#XA0;3</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;<EM>
In some games, cards are moved from one hand to another,
Write a Deck method called </EM></FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3><EM>deal_hands</EM></FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3><EM> that takes two
or from a hand back to the deck. You can use <CODE>move_cards</CODE>
for any of these operations: <TT>self</TT> can be either a Deck
or a Hand, and <TT>hand</TT>, despite the name, can also be a <TT>Deck</TT>.
<DIV CLASS="theorem">'''Exercise&#XA0;3'''&#XA0;&#XA0;''
Write a Deck method called ''<CODE>''deal_hands''</CODE>'' that takes two
parameters, the number of hands and the number of cards per
parameters, the number of hands and the number of cards per
hand, and that creates new Hand objects, deals the appropriate
hand, and that creates new Hand objects, deals the appropriate
number of cards per hand, and returns a list of Hand objects.
number of cards per hand, and returns a list of Hand objects.
</EM></FONT></FONT></DIV><P><FONT COLOR=black><FONT SIZE=3>Inheritance is a useful feature. Some programs that would be
''</DIV>
Inheritance is a useful feature. Some programs that would be
repetitive without inheritance can be written more elegantly
repetitive without inheritance can be written more elegantly
with it. Inheritance can facilitate code reuse, since you can
with it. Inheritance can facilitate code reuse, since you can
Line 302: Line 473:
them. In some cases, the inheritance structure reflects the natural
them. In some cases, the inheritance structure reflects the natural
structure of the problem, which makes the program easier to
structure of the problem, which makes the program easier to
understand.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>On the other hand, inheritance can make programs difficult to read.
understand.
 
On the other hand, inheritance can make programs difficult to read.
When a method is invoked, it is sometimes not clear where to find its
When a method is invoked, it is sometimes not clear where to find its
definition. The relevant code may be scattered among several modules.
definition. The relevant code may be scattered among several modules.
Also, many of the things that can be done using inheritance can be
Also, many of the things that can be done using inheritance can be
done as well or better without it. </FONT></FONT></P><H2 CLASS="section"><A NAME="toc200"></A><A NAME="htoc220"><FONT COLOR=black><FONT SIZE=3>18.8</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;Class diagrams</FONT></FONT></H2><P><FONT COLOR=black><FONT SIZE=3>So far we have seen stack diagrams, which show the state of
done as well or better without it.
 
=== 18.8&#XA0;&#XA0;Class diagrams ===
 
So far we have seen stack diagrams, which show the state of
a program, and object diagrams, which show the attributes
a program, and object diagrams, which show the attributes
of an object and their values. These diagrams represent a snapshot
of an object and their values. These diagrams represent a snapshot
in the execution of a program, so they change as the program
in the execution of a program, so they change as the program
runs.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>They are also highly detailed; for some purposes, too
runs.
 
They are also highly detailed; for some purposes, too
detailed. A class diagrams is a more abstract representation
detailed. A class diagrams is a more abstract representation
of the structure of a program. Instead of showing individual
of the structure of a program. Instead of showing individual
objects, it shows classes and the relationships between them.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>There are several kinds of relationship between classes:</FONT></FONT></P><UL CLASS="itemize"><LI CLASS="li-itemize"><FONT COLOR=black><FONT SIZE=3>Objects in one class might contain references to objects
objects, it shows classes and the relationships between them.
 
There are several kinds of relationship between classes:
 
*Objects in one class might contain references to objects
in another class. For example, each Rectangle contains a reference
in another class. For example, each Rectangle contains a reference
to a Point, and each Deck contains references to many Cards.
to a Point, and each Deck contains references to many Cards.
This kind of relationship is called </FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>HAS-A</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, as in, &#X201C;a Rectangle
This kind of relationship is called '''HAS-A''', as in, &#X201C;a Rectangle
has a Point.&#X201D;</FONT></FONT></LI><LI CLASS="li-itemize"><FONT COLOR=black><FONT SIZE=3>One class might inherit from another. This relationship
has a Point.&#X201D;
is called </FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>IS-A</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, as in, &#X201C;a Hand is a kind of a Deck.&#X201D;</FONT></FONT></LI><LI CLASS="li-itemize"><FONT COLOR=black><FONT SIZE=3>One class might depend on another in the sense that changes
 
in one class would require changes in the other.</FONT></FONT></LI></UL><P><A NAME="@default1639"></A><FONT COLOR=black><FONT SIZE=3>
*One class might inherit from another. This relationship
</FONT></FONT><A NAME="@default1640"></A><FONT COLOR=black><FONT SIZE=3>
is called '''IS-A''', as in, &#X201C;a Hand is a kind of a Deck.&#X201D;
</FONT></FONT><A NAME="@default1641"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1642"></A><FONT COLOR=black><FONT SIZE=3>
*One class might depend on another in the sense that changes
</FONT></FONT><A NAME="@default1643"></A></P><P><FONT COLOR=black><FONT SIZE=3>A </FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>class diagram</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3> is a graphical representation of these
in one class would require changes in the other.
relationships</FONT></FONT><SUP><A NAME="text31" HREF="#note31"><FONT COLOR=black><FONT SIZE=3>2</FONT></FONT></A></SUP><FONT COLOR=black><FONT SIZE=3>. For example, this diagram shows the
 
relationships between </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Card</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Deck</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> and </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Hand</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.</FONT></FONT></P><DIV CLASS="center"><FONT COLOR=black><FONT SIZE=3><IMG SRC="book027.png"></FONT></FONT></DIV><P><FONT COLOR=black><FONT SIZE=3>The arrow with a hollow triangle head represents an IS-A
 
 
 
 
 
 
A '''class diagram''' is a graphical representation of these
relationships<SUP>2</SUP>. For example, this diagram shows the
relationships between <TT>Card</TT>, <TT>Deck</TT> and <TT>Hand</TT>.
<DIV CLASS="center"><IMG SRC="book027.png"></DIV>
The arrow with a hollow triangle head represents an IS-A
relationship; in this case it indicates that Hand inherits
relationship; in this case it indicates that Hand inherits
from Deck.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>The standard arrow head represents a HAS-A
from Deck.
 
The standard arrow head represents a HAS-A
relationship; in this case a Deck has references to Card
relationship; in this case a Deck has references to Card
objects.</FONT></FONT></P><P><A NAME="@default1644"></A></P><P><FONT COLOR=black><FONT SIZE=3>The star (</FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>*</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>) near the arrow head is a  
objects.
</FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>multiplicity</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>; it indicates how many Cards a Deck has.
 
A multiplicity can be a simple number, like </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>52</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, a range,
The star (<TT>*</TT>) near the arrow head is a  
like </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>5..7</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> or a star, which indicates that a Deck can
'''multiplicity'''; it indicates how many Cards a Deck has.
have any number of Cards.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>A more detailed diagram might show that a Deck actually
A multiplicity can be a simple number, like <TT>52</TT>, a range,
contains a </FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>list</EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3> of Cards, but built-in types
like <TT>5..7</TT> or a star, which indicates that a Deck can
like list and dict are usually not included in class diagrams.</FONT></FONT></P><DIV CLASS="theorem"><FONT COLOR=black><FONT SIZE=3><B>Exercise&#XA0;4</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;<EM>
have any number of Cards.
Read </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>TurtleWorld.py</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>, </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>World.py</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> and </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>Gui.py</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>
 
A more detailed diagram might show that a Deck actually
contains a ''list'' of Cards, but built-in types
like list and dict are usually not included in class diagrams.
<DIV CLASS="theorem">'''Exercise&#XA0;4'''&#XA0;&#XA0;''
Read ''''<TT>TurtleWorld.py</TT>'''', ''''<TT>World.py</TT>'''' and ''''<TT>Gui.py</TT>''''
and draw a class diagram that shows the relationships among
and draw a class diagram that shows the relationships among
the classes defined there.
the classes defined there.
</EM></FONT></FONT></DIV><H2 CLASS="section"><A NAME="toc201"></A><A NAME="htoc221"><FONT COLOR=black><FONT SIZE=3>18.9</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;Debugging</FONT></FONT></H2><P><FONT COLOR=black><FONT SIZE=3>
''</DIV>=== 18.9&#XA0;&#XA0;Debugging ===
</FONT></FONT><A NAME="@default1645"></A></P><P><FONT COLOR=black><FONT SIZE=3>Inheritance can make debugging a challenge because when you
 
 
 
 
Inheritance can make debugging a challenge because when you
invoke a method on an object, you might not know which method
invoke a method on an object, you might not know which method
will be invoked.</FONT></FONT></P><P><A NAME="@default1646"></A></P><P><FONT COLOR=black><FONT SIZE=3>Suppose you are writing a function that works with Hand objects.
will be invoked.
 
Suppose you are writing a function that works with Hand objects.
You would like it to work with all kinds of Hands, like
You would like it to work with all kinds of Hands, like
PokerHands, BridgeHands, etc. If you invoke a method like
PokerHands, BridgeHands, etc. If you invoke a method like
</FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>shuffle</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, you might get the one defined in </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Deck</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>,
<TT>shuffle</TT>, you might get the one defined in <TT>Deck</TT>,
but if any of the subclasses override this method, you&#X2019;ll
but if any of the subclasses override this method, you&#X2019;ll
get that version instead. </FONT></FONT></P><P><A NAME="@default1647"></A></P><P><FONT COLOR=black><FONT SIZE=3>Any time you are unsure about the flow of execution through your
get that version instead.  
 
Any time you are unsure about the flow of execution through your
program, the simplest solution is to add print statements at the
program, the simplest solution is to add print statements at the
beginning of the relevant methods. If </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Deck.shuffle</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> prints a
beginning of the relevant methods. If <TT>Deck.shuffle</TT> prints a
message that says something like </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Running Deck.shuffle</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, then as
message that says something like <TT>Running Deck.shuffle</TT>, then as
the program runs it traces the flow of execution.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>As an alternative, you could use this function, which takes an
the program runs it traces the flow of execution.
 
As an alternative, you could use this function, which takes an
object and a method name (as a string) and returns the class that
object and a method name (as a string) and returns the class that
provides the definition of the method:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>def find_defining_class(obj, meth_name):
provides the definition of the method:
<PRE CLASS="verbatim">def find_defining_class(obj, meth_name):
     for ty in type(obj).mro():
     for ty in type(obj).mro():
         if meth_name in ty.__dict__:
         if meth_name in ty.__dict__:
             return ty
             return ty
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>Here&#X2019;s an example:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>&gt;&gt;&gt; hand = Hand()
</PRE>
Here&#X2019;s an example:
<PRE CLASS="verbatim">&gt;&gt;&gt; hand = Hand()
&gt;&gt;&gt; print find_defining_class(hand, 'shuffle')
&gt;&gt;&gt; print find_defining_class(hand, 'shuffle')
&lt;class 'Card.Deck'&gt;
&lt;class 'Card.Deck'&gt;
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>So the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>shuffle</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> method for this Hand is the one in </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Deck</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.</FONT></FONT></P><P><A NAME="@default1648"></A><FONT COLOR=black><FONT SIZE=3>
</PRE>
</FONT></FONT><A NAME="@default1649"></A><FONT COLOR=black><FONT SIZE=3>
So the <TT>shuffle</TT> method for this Hand is the one in <TT>Deck</TT>.
</FONT></FONT><A NAME="@default1650"></A></P><P><CODE><FONT COLOR=black><FONT SIZE=3>find_defining_class</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> uses the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>mro</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> method to get the list
 
 
 
 
 
<CODE>find_defining_class</CODE> uses the <TT>mro</TT> method to get the list
of class objects (types) that will be searched for methods. &#X201C;MRO&#X201D;
of class objects (types) that will be searched for methods. &#X201C;MRO&#X201D;
stands for &#X201C;method resolution order.&#X201D;</FONT></FONT></P><P><A NAME="@default1651"></A><FONT COLOR=black><FONT SIZE=3>
stands for &#X201C;method resolution order.&#X201D;
</FONT></FONT><A NAME="@default1652"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1653"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1654"></A></P><P><FONT COLOR=black><FONT SIZE=3>Here&#X2019;s a program design suggestion: whenever you override a method,
 
 
 
 
Here&#X2019;s a program design suggestion: whenever you override a method,
the interface of the new method should be the same as the old. It
the interface of the new method should be the same as the old. It
should take the same parameters, return the same type, and obey the
should take the same parameters, return the same type, and obey the
Line 373: Line 595:
will find that any function designed to work with an instance of a
will find that any function designed to work with an instance of a
superclass, like a Deck, will also work with instances of subclasses
superclass, like a Deck, will also work with instances of subclasses
like a Hand or PokerHand.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>If you violate this rule, your code will collapse like (sorry)
like a Hand or PokerHand.
a house of cards.</FONT></FONT></P><H2 CLASS="section"><A NAME="toc202"></A><A NAME="htoc222"><FONT COLOR=black><FONT SIZE=3>18.10</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;Glossary</FONT></FONT></H2><DL CLASS="description"><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>encode:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> To represent one set of values using another
 
If you violate this rule, your code will collapse like (sorry)
a house of cards.
=== 18.10&#XA0;&#XA0;Glossary ===
 
<DL CLASS="description"><DT CLASS="dt-description">'''encode:'''</DT><DD CLASS="dd-description"> To represent one set of values using another
set of values by constructing a mapping between them.
set of values by constructing a mapping between them.
</FONT></FONT><A NAME="@default1655"></A></DD><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>class attribute:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> An attribute associated with a class
</DD><DT CLASS="dt-description">'''class attribute:'''</DT><DD CLASS="dd-description"> An attribute associated with a class
object. Class attributes are defined inside
object. Class attributes are defined inside
a class definition but outside any method.
a class definition but outside any method.
</FONT></FONT><A NAME="@default1656"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1657"></A></DD><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>instance attribute:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> An attribute associated with an
</DD><DT CLASS="dt-description">'''instance attribute:'''</DT><DD CLASS="dd-description"> An attribute associated with an
instance of a class.
instance of a class.
</FONT></FONT><A NAME="@default1658"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1659"></A></DD><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>veneer:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> A method or function that provides a different
</DD><DT CLASS="dt-description">'''veneer:'''</DT><DD CLASS="dd-description"> A method or function that provides a different
interface to another function without doing much computation.
interface to another function without doing much computation.
</FONT></FONT><A NAME="@default1660"></A></DD><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>inheritance:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> The ability to define a new class that is a
</DD><DT CLASS="dt-description">'''inheritance:'''</DT><DD CLASS="dd-description"> The ability to define a new class that is a
modified version of a previously defined class.
modified version of a previously defined class.
</FONT></FONT><A NAME="@default1661"></A></DD><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>parent class:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> The class from which a child class inherits.
</DD><DT CLASS="dt-description">'''parent class:'''</DT><DD CLASS="dd-description"> The class from which a child class inherits.
</FONT></FONT><A NAME="@default1662"></A></DD><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>child class:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> A new class created by inheriting from an
</DD><DT CLASS="dt-description">'''child class:'''</DT><DD CLASS="dd-description"> A new class created by inheriting from an
existing class; also called a &#X201C;subclass.&#X201D;
existing class; also called a &#X201C;subclass.&#X201D;
</FONT></FONT><A NAME="@default1663"></A></DD><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>IS-A relationship:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> The relationship between a child class
</DD><DT CLASS="dt-description">'''IS-A relationship:'''</DT><DD CLASS="dd-description"> The relationship between a child class
and its parent class.
and its parent class.
</FONT></FONT><A NAME="@default1664"></A></DD><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>HAS-A relationship:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> The relationship between two classes
</DD><DT CLASS="dt-description">'''HAS-A relationship:'''</DT><DD CLASS="dd-description"> The relationship between two classes
where instances of one class contain references to instances of
where instances of one class contain references to instances of
the other.
the other.
</FONT></FONT><A NAME="@default1665"></A></DD><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>class diagram:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> A diagram that shows the classes in a program
</DD><DT CLASS="dt-description">'''class diagram:'''</DT><DD CLASS="dd-description"> A diagram that shows the classes in a program
and the relationships between them.
and the relationships between them.
</FONT></FONT><A NAME="@default1666"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1667"></A></DD><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>multiplicity:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> A notation in a class diagram that shows, for
</DD><DT CLASS="dt-description">'''multiplicity:'''</DT><DD CLASS="dd-description"> A notation in a class diagram that shows, for
a HAS-A relationship, how many references there are to instances
a HAS-A relationship, how many references there are to instances
of another class.
of another class.
</FONT></FONT><A NAME="@default1668"></A></DD></DL><H2 CLASS="section"><A NAME="toc203"></A><A NAME="htoc223"><FONT COLOR=black><FONT SIZE=3>18.11</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;Exercises</FONT></FONT></H2><DIV CLASS="theorem"><FONT COLOR=black><FONT SIZE=3><B>Exercise&#XA0;5</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;<EM>
</DD></DL>=== 18.11&#XA0;&#XA0;Exercises ===
</EM></FONT></FONT><A NAME="@default1669"></A><P><FONT COLOR=black><FONT SIZE=3><EM>The following are the possible hands in poker, in increasing order
 
of value (and decreasing order of probability):</EM></FONT></FONT></P><DL CLASS="description"><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><EM><B>pair:</B></EM></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3><EM> two cards with the same rank
<DIV CLASS="theorem">'''Exercise&#XA0;5'''&#XA0;&#XA0;''
</EM></FONT></FONT></DD><DT CLASS="dt-description"><EM><FONT COLOR=black><FONT SIZE=3><EM><B>two pair:</B></EM></FONT></FONT></EM></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3><EM> two pairs of cards with the same rank
''
</EM></FONT></FONT></DD><DT CLASS="dt-description"><EM><FONT COLOR=black><FONT SIZE=3><EM><B>three of a kind:</B></EM></FONT></FONT></EM></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3><EM> three cards with the same rank
''The following are the possible hands in poker, in increasing order
</EM></FONT></FONT></DD><DT CLASS="dt-description"><EM><FONT COLOR=black><FONT SIZE=3><EM><B>straight:</B></EM></FONT></FONT></EM></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3><EM> five cards with ranks in sequence (aces can
of value (and decreasing order of probability):''
be high or low, so </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>Ace-2-3-4-5</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> is a straight and so is </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>10-Jack-Queen-King-Ace</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>, but </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>Queen-King-Ace-2-3</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> is not.)
<DL CLASS="description"><DT CLASS="dt-description">'''''pair:'''''</DT><DD CLASS="dd-description">'' two cards with the same rank
</EM></FONT></FONT></DD><DT CLASS="dt-description"><EM><FONT COLOR=black><FONT SIZE=3><EM><B>flush:</B></EM></FONT></FONT></EM></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3><EM> five cards with the same suit
''</DD><DT CLASS="dt-description">'''''''two pair:'''''''</DT><DD CLASS="dd-description">'' two pairs of cards with the same rank
</EM></FONT></FONT></DD><DT CLASS="dt-description"><EM><FONT COLOR=black><FONT SIZE=3><EM><B>full house:</B></EM></FONT></FONT></EM></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3><EM> three cards with one rank, two cards with another
''</DD><DT CLASS="dt-description">'''''''three of a kind:'''''''</DT><DD CLASS="dd-description">'' three cards with the same rank
</EM></FONT></FONT></DD><DT CLASS="dt-description"><EM><FONT COLOR=black><FONT SIZE=3><EM><B>four of a kind:</B></EM></FONT></FONT></EM></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3><EM> four cards with the same rank
''</DD><DT CLASS="dt-description">'''''''straight:'''''''</DT><DD CLASS="dd-description">'' five cards with ranks in sequence (aces can
</EM></FONT></FONT></DD><DT CLASS="dt-description"><EM><FONT COLOR=black><FONT SIZE=3><EM><B>straight flush:</B></EM></FONT></FONT></EM></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3><EM> five cards in sequence (as defined above) and
be high or low, so ''''<TT>Ace-2-3-4-5</TT>'''' is a straight and so is ''''<TT>10-Jack-Queen-King-Ace</TT>'''', but ''''<TT>Queen-King-Ace-2-3</TT>'''' is not.)
''</DD><DT CLASS="dt-description">'''''''flush:'''''''</DT><DD CLASS="dd-description">'' five cards with the same suit
''</DD><DT CLASS="dt-description">'''''''full house:'''''''</DT><DD CLASS="dd-description">'' three cards with one rank, two cards with another
''</DD><DT CLASS="dt-description">'''''''four of a kind:'''''''</DT><DD CLASS="dd-description">'' four cards with the same rank
''</DD><DT CLASS="dt-description">'''''''straight flush:'''''''</DT><DD CLASS="dd-description">'' five cards in sequence (as defined above) and
with the same suit
with the same suit
</EM></FONT></FONT></DD></DL><P><FONT COLOR=black><FONT SIZE=3><EM>
''</DD></DL>
''
The goal of these exercises is to estimate
The goal of these exercises is to estimate
the probability of drawing these various hands.</EM></FONT></FONT></P><OL CLASS="enumerate" type=1><LI CLASS="li-enumerate"><FONT COLOR=black><FONT SIZE=3><EM>Download the following files from </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>thinkpython.com/code</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>:</EM></FONT></FONT><DL CLASS="description"><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><EM><B><TT>Card.py</TT></B></EM></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3><EM>: A complete version of the </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>Card</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>,
the probability of drawing these various hands.''
</EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>Deck</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> and </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>Hand</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> classes in this chapter.</EM></FONT></FONT></DD><DT CLASS="dt-description"><EM><FONT COLOR=black><FONT SIZE=3><EM><B><TT>PokerHand.py</TT></B></EM></FONT></FONT></EM></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3><EM>: An incomplete implementation of a class
 
that represents a poker hand, and some code that tests it.</EM></FONT></FONT></DD></DL></LI><LI CLASS="li-enumerate"><EM><FONT COLOR=black><FONT SIZE=3><EM>If you run </EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM><TT>PokerHand.py</TT></EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM>, it deals six 7-card poker hands
*''Download the following files from ''''<TT>thinkpython.com/code</TT>'''':''<DL CLASS="description"><DT CLASS="dt-description">'''''<TT>Card.py</TT>'''''</DT><DD CLASS="dd-description">'': A complete version of the ''''<TT>Card</TT>'''',
''''<TT>Deck</TT>'''' and ''''<TT>Hand</TT>'''' classes in this chapter.''</DD><DT CLASS="dt-description">'''''''<TT>PokerHand.py</TT>'''''''</DT><DD CLASS="dd-description">'': An incomplete implementation of a class
that represents a poker hand, and some code that tests it.''</DD></DL>
 
*''''If you run ''''''''<TT>PokerHand.py</TT>'''''''', it deals six 7-card poker hands
and checks to see if any of them contains a flush. Read this
and checks to see if any of them contains a flush. Read this
code carefully before you go on.</EM></FONT></FONT></EM></LI><LI CLASS="li-enumerate"><EM><FONT COLOR=black><FONT SIZE=3><EM>Add methods to </EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM><TT>PokerHand.py</TT></EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM> named </EM></FONT></FONT></EM><CODE><EM><FONT COLOR=black><FONT SIZE=3><EM>has_pair</EM></FONT></FONT></EM></CODE><EM><FONT COLOR=black><FONT SIZE=3><EM>,
code carefully before you go on.''''
</EM></FONT></FONT></EM><CODE><EM><FONT COLOR=black><FONT SIZE=3><EM>has_twopair</EM></FONT></FONT></EM></CODE><EM><FONT COLOR=black><FONT SIZE=3><EM>, etc. that return True or False according to
 
*''''Add methods to ''''''''<TT>PokerHand.py</TT>'''''''' named ''''<CODE>''''has_pair''''</CODE>'''',
''''<CODE>''''has_twopair''''</CODE>'''', etc. that return True or False according to
whether or not the hand meets the relevant criteria. Your code should
whether or not the hand meets the relevant criteria. Your code should
work correctly for &#X201C;hands&#X201D; that contain any number of cards
work correctly for &#X201C;hands&#X201D; that contain any number of cards
(although 5 and 7 are the most common sizes).</EM></FONT></FONT></EM></LI><LI CLASS="li-enumerate"><EM><FONT COLOR=black><FONT SIZE=3><EM>Write a method named </EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM><TT>classify</TT></EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM> that figures out
(although 5 and 7 are the most common sizes).''''
 
*''''Write a method named ''''''''<TT>classify</TT>'''''''' that figures out
the highest-value classification for a hand and sets the
the highest-value classification for a hand and sets the
</EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM><TT>label</TT></EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM> attribute accordingly. For example, a 7-card hand
''''''''<TT>label</TT>'''''''' attribute accordingly. For example, a 7-card hand
might contain a flush and a pair; it should be labeled &#X201C;flush&#X201D;.</EM></FONT></FONT></EM></LI><LI CLASS="li-enumerate"><EM><FONT COLOR=black><FONT SIZE=3><EM>When you are convinced that your classification methods are
might contain a flush and a pair; it should be labeled &#X201C;flush&#X201D;.''''
 
*''''When you are convinced that your classification methods are
working, the next step is to estimate the probabilities of the various
working, the next step is to estimate the probabilities of the various
hands. Write a function in </EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM><TT>PokerHand.py</TT></EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM> that shuffles a deck of
hands. Write a function in ''''''''<TT>PokerHand.py</TT>'''''''' that shuffles a deck of
cards, divides it into hands, classifies the hands, and counts the
cards, divides it into hands, classifies the hands, and counts the
number of times various classifications appear.</EM></FONT></FONT></EM></LI><LI CLASS="li-enumerate"><EM><FONT COLOR=black><FONT SIZE=3><EM>Print a table of the classifications and their probabilities.
number of times various classifications appear.''''
 
*''''Print a table of the classifications and their probabilities.
Run your program with larger and larger numbers of hands until the
Run your program with larger and larger numbers of hands until the
output values converge to a reasonable degree of accuracy. Compare
output values converge to a reasonable degree of accuracy. Compare
your results to the values at </EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM><TT>wikipedia.org/wiki/Hand_rankings</TT></EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM>.</EM></FONT></FONT></EM></LI></OL></DIV><DIV CLASS="theorem"><FONT COLOR=black><FONT SIZE=3><B>Exercise&#XA0;6</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;</FONT></FONT><P><A NAME="@default1670"></A><FONT COLOR=black><FONT SIZE=3><EM>
your results to the values at ''''''''<TT>wikipedia.org/wiki/Hand_rankings</TT>''''''''.''''
</EM></FONT></FONT><A NAME="@default1671"></A></P><P><FONT COLOR=black><FONT SIZE=3><EM>This exercise uses TurtleWorld from Chapter&#XA0;</EM></FONT></FONT><A HREF="book005.html#turtlechap"><FONT COLOR=black><FONT SIZE=3><EM>4</EM></FONT></FONT></A><FONT COLOR=black><FONT SIZE=3><EM>.
 
</DIV><DIV CLASS="theorem">'''Exercise&#XA0;6'''&#XA0;&#XA0;
''
''
 
''This exercise uses TurtleWorld from Chapter&#XA0;''''4''''.
You will write code that makes Turtles play tag. If you
You will write code that makes Turtles play tag. If you
are not familiar with the rules of tag, see
are not familiar with the rules of tag, see
</EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>wikipedia.org/wiki/Tag_(game)</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>.</EM></FONT></FONT></P><OL CLASS="enumerate" type=1><LI CLASS="li-enumerate"><FONT COLOR=black><FONT SIZE=3><EM>Download </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>thinkpython.com/code/Wobbler.py</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> and run it. You
''''<TT>wikipedia.org/wiki/Tag_(game)</TT>''''.''
 
*''Download ''''<TT>thinkpython.com/code/Wobbler.py</TT>'''' and run it. You
should see a TurtleWorld with three Turtles. If you press the
should see a TurtleWorld with three Turtles. If you press the
</EM></FONT></FONT><FONT SIZE=3><EM><FONT COLOR=purple>Run</FONT></EM></FONT><FONT COLOR=black><FONT SIZE=3><EM> button, the Turtles wander at random.</EM></FONT></FONT></LI><LI CLASS="li-enumerate"><FONT COLOR=black><FONT SIZE=3><EM>Read the code and make sure you understand how it works.
''''Run'''' button, the Turtles wander at random.''
The </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>Wobbler</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> class inherits from </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>Turtle</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>, which means
 
that the </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>Turtle</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> methods </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>lt</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>, </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>rt</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>, </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>fd</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>
*''Read the code and make sure you understand how it works.
and </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>bk</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> work on Wobblers.</EM></FONT></FONT><P><FONT COLOR=black><FONT SIZE=3><EM>The </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>step</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> method gets invoked by TurtleWorld. It invokes  
The ''''<TT>Wobbler</TT>'''' class inherits from ''''<TT>Turtle</TT>'''', which means
</EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>steer</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>, which turns the Turtle in the desired direction,
that the ''''<TT>Turtle</TT>'''' methods ''''<TT>lt</TT>'''', ''''<TT>rt</TT>'''', ''''<TT>fd</TT>''''
</EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>wobble</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>, which makes a random turn in proportion to the Turtle&#X2019;s
and ''''<TT>bk</TT>'''' work on Wobblers.''
clumsiness, and </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>move</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>, which moves forward a few pixels,
''The ''''<TT>step</TT>'''' method gets invoked by TurtleWorld. It invokes  
depending on the Turtle&#X2019;s speed.</EM></FONT></FONT></P><P><A NAME="@default1672"></A></P></LI><LI CLASS="li-enumerate"><FONT COLOR=black><FONT SIZE=3><EM>Create a file named </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>Tagger.py</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>. Import everything from
''''<TT>steer</TT>'''', which turns the Turtle in the desired direction,
</EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>Wobbler</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>, then define a class named </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>Tagger</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> that inherits
''''<TT>wobble</TT>'''', which makes a random turn in proportion to the Turtle&#X2019;s
from </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>Wobbler</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>. Call </EM></FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3><EM>make_world</EM></FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3><EM> passing the </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>Tagger</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> class object as an argument.</EM></FONT></FONT></LI><LI CLASS="li-enumerate"><FONT COLOR=black><FONT SIZE=3><EM>Add a </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>steer</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> method to </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>Tagger</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> to override the one in
clumsiness, and ''''<TT>move</TT>'''', which moves forward a few pixels,
</EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>Wobbler</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>. As a starting place, write a version that always
depending on the Turtle&#X2019;s speed.''
 
*''Create a file named ''''<TT>Tagger.py</TT>''''. Import everything from
''''<TT>Wobbler</TT>'''', then define a class named ''''<TT>Tagger</TT>'''' that inherits
from ''''<TT>Wobbler</TT>''''. Call ''<CODE>''make_world''</CODE>'' passing the ''''<TT>Tagger</TT>'''' class object as an argument.''
 
*''Add a ''''<TT>steer</TT>'''' method to ''''<TT>Tagger</TT>'''' to override the one in
''''<TT>Wobbler</TT>''''. As a starting place, write a version that always
points the Turtle toward the origin. Hint: use the math function
points the Turtle toward the origin. Hint: use the math function
</EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>atan2</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> and the Turtle attributes </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>x</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>, </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>y</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> and
''''<TT>atan2</TT>'''' and the Turtle attributes ''''<TT>x</TT>'''', ''''<TT>y</TT>'''' and
</EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>heading</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>.</EM></FONT></FONT></LI><LI CLASS="li-enumerate"><FONT COLOR=black><FONT SIZE=3><EM>Modify </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>steer</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> so that the Turtles stay in bounds.
''''<TT>heading</TT>''''.''
For debugging, you might want to use the </EM></FONT></FONT><FONT SIZE=3><EM><FONT COLOR=purple>Step</FONT></EM></FONT><FONT COLOR=black><FONT SIZE=3><EM> button,
 
which invokes </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>step</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> once on each Turtle.</EM></FONT></FONT></LI><LI CLASS="li-enumerate"><FONT COLOR=black><FONT SIZE=3><EM>Modify </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>steer</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> so that each Turtle points toward its nearest
*''Modify ''''<TT>steer</TT>'''' so that the Turtles stay in bounds.
neighbor. Hint: Turtles have an attribute, </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>world</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>, that is a
For debugging, you might want to use the ''''Step'''' button,
which invokes ''''<TT>step</TT>'''' once on each Turtle.''
 
*''Modify ''''<TT>steer</TT>'''' so that each Turtle points toward its nearest
neighbor. Hint: Turtles have an attribute, ''''<TT>world</TT>'''', that is a
reference to the TurtleWorld they live in, and the TurtleWorld has
reference to the TurtleWorld they live in, and the TurtleWorld has
an attribute, </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>animals</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>, that is a list of all Turtles in the
an attribute, ''''<TT>animals</TT>'''', that is a list of all Turtles in the
world.</EM></FONT></FONT></LI><LI CLASS="li-enumerate"><FONT COLOR=black><FONT SIZE=3><EM>Modify </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>steer</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> so the Turtles play tag. You can add methods
world.''
to </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>Tagger</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> and you can override </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>steer</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> and
 
</EM></FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3><EM>__init__</EM></FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3><EM>, but you may not modify or override </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>step</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>, </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>wobble</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> or </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>move</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>. Also, </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>steer</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> is allowed to change the
*''Modify ''''<TT>steer</TT>'''' so the Turtles play tag. You can add methods
heading of the Turtle but not the position.</EM></FONT></FONT><P><FONT COLOR=black><FONT SIZE=3><EM>Adjust the rules and your </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>steer</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> method for good quality play;
to ''''<TT>Tagger</TT>'''' and you can override ''''<TT>steer</TT>'''' and
''<CODE>''__init__''</CODE>'', but you may not modify or override ''''<TT>step</TT>'''', ''''<TT>wobble</TT>'''' or ''''<TT>move</TT>''''. Also, ''''<TT>steer</TT>'''' is allowed to change the
heading of the Turtle but not the position.''
''Adjust the rules and your ''''<TT>steer</TT>'''' method for good quality play;
for example, it should be possible for the slow Turtle to tag the
for example, it should be possible for the slow Turtle to tag the
faster Turtles eventually.</EM></FONT></FONT></P></LI></OL><P><FONT COLOR=black><FONT SIZE=3><EM>You can get my solution from </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>thinkpython.com/code/Tagger.py</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>.
faster Turtles eventually.''
</EM></FONT></FONT></P></DIV><HR CLASS="footnoterule"><DL CLASS="thefootnotes"><DT CLASS="dt-thefootnotes"><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="note30" HREF="#text30"><FONT COLOR=black><FONT SIZE=3>1</FONT></FONT></A></DT><DD CLASS="dd-thefootnotes"><FONT COLOR=black><FONT SIZE=3>See <TT>wikipedia.org/wiki/Bottom_dealing</TT>.
''You can get my solution from ''''<TT>thinkpython.com/code/Tagger.py</TT>''''.
</FONT></FONT></DD><DT CLASS="dt-thefootnotes"><A NAME="note31" HREF="#text31"><FONT COLOR=black><FONT SIZE=3>2</FONT></FONT></A></DT><DD CLASS="dd-thefootnotes"><FONT COLOR=black><FONT SIZE=3>The diagrams I am using here are similar to UML
''
</DIV><HR CLASS="footnoterule"><DL CLASS="thefootnotes"><DT CLASS="dt-thefootnotes">
1</DT><DD CLASS="dd-thefootnotes">See <TT>wikipedia.org/wiki/Bottom_dealing</TT>.
</DD><DT CLASS="dt-thefootnotes">2</DT><DD CLASS="dd-thefootnotes">The diagrams I am using here are similar to UML
(see <TT>wikipedia.org/wiki/Unified_Modeling_Language</TT>), with a few
(see <TT>wikipedia.org/wiki/Unified_Modeling_Language</TT>), with a few
simplifications.
simplifications.
</FONT></FONT></DD></DL>
</DD></DL>
<HR>
<HR>
<A HREF="book018.html"><IMG SRC="previous_motif.gif" ALT="Previous"></A>
<IMG SRC="previous_motif.gif" ALT="Previous">
<A HREF="index.html"><IMG SRC="contents_motif.gif" ALT="Up"></A>
<IMG SRC="contents_motif.gif" ALT="Up">
<A HREF="book020.html"><IMG SRC="next_motif.gif" ALT="Next"></A>
<IMG SRC="next_motif.gif" ALT="Next">
</BODY>
</HTML>

Latest revision as of 20:09, 18 May 2009

Chapter 18  Inheritance

In this chapter we will develop classes to represent playing cards, decks of cards, and poker hands. If you don’t play poker, you can read about it at wikipedia.org/wiki/Poker, but you don’t have to; I’ll tell you what you need to know for the exercises.



If you are not familiar with Anglo-American playing cards, you can read about them at wikipedia.org/wiki/Playing_cards.

18.1  Card objects

There are fifty-two cards in a deck, each of which belongs to one of four suits and one of thirteen ranks. The suits are Spades, Hearts, Diamonds, and Clubs (in descending order in bridge). The ranks are Ace, 2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, and King. Depending on the game that you are playing, an Ace may be higher than King or lower than 2.



If we want to define a new object to represent a playing card, it is obvious what the attributes should be: rank and suit. It is not as obvious what type the attributes should be. One possibility is to use strings containing words like 'Spade' for suits and 'Queen' for ranks. One problem with this implementation is that it would not be easy to compare cards to see which had a higher rank or suit.




An alternative is to use integers to encode the ranks and suits. In this context, “encode” means that we are going to define a mapping between numbers and suits, or between numbers and ranks. This kind of encoding is not meant to be a secret (that would be “encryption”).

For example, this table shows the suits and the corresponding integer codes:

Spades↦3
Hearts↦2
Diamonds↦1
Clubs↦0

This code makes it easy to compare cards; because higher suits map to higher numbers, we can compare suits by comparing their codes.

The mapping for ranks is fairly obvious; each of the numerical ranks maps to the corresponding integer, and for face cards:

Jack↦11
Queen↦12
King↦13

I am using the ↦ symbol to make is clear that these mappings are not part of the Python program. They are part of the program design, but they don’t appear explicitly in the code.



The class definition for Card looks like this:

class Card:
    """represents a standard playing card."""

    def __init__(self, suit=0, rank=2):
        self.suit = suit
        self.rank = rank

As usual, the init method takes an optional parameter for each attribute. The default card is the 2 of Clubs.



To create a Card, you call Card with the suit and rank of the card you want.

queen_of_diamonds = Card(1, 12)

18.2  Class attributes

In order to print Card objects in a way that people can easily read, we need a mapping from the integer codes to the corresponding ranks and suits. A natural way to do that is with lists of strings. We assign these lists to class attributes:

# inside class Card:

    suit_names = ['Clubs', 'Diamonds', 'Hearts', 'Spades']
    rank_names = [None, 'Ace', '2', '3', '4', '5', '6', '7', 
              '8', '9', '10', 'Jack', 'Queen', 'King']

    def __str__(self):
        return '%s of %s' % (Card.rank_names[self.rank],
                             Card.suit_names[self.suit])

Variables like suit_names and rank_names, which are defined inside a class but outside of any method, are called class attributes because they are associated with the class object Card.



This term distinguished them from variables like suit and rank, which are called instance attributes because they are associated with a particular instance.

Both kinds of attribute are accessed using dot notation. For example, in __str__, self is a Card object, and self.rank is its rank. Similarly, Card is a class object, and Card.rank_names is a list of strings associated with the class.

Every card has its own suit and rank, but there is only one copy of suit_names and rank_names.

Putting it all together, the expression Card.rank_names[self.rank] means “use the attribute rank from the object self as an index into the list rank_names from the class Card, and select the appropriate string.”

The first element of rank_names is None because there is no card with rank zero. By including None as a place-keeper, we get a mapping with the nice property that the index 2 maps to the string '2', and so on. To avoid this tweak, we could have used a dictionary instead of a list.

With the methods we have so far, we can create and print cards:

>>> card1 = Card(2, 11)
>>> print card1
Jack of Hearts

Here is a diagram that shows the Card class object and one Card instance:



<IMG SRC="book026.png">

Card is a class object, so it has type type. card1 has type Card. (To save space, I didn’t draw the contents of suit_names and rank_names).

18.3  Comparing cards

For built-in types, there are conditional operators (<, >, ==, etc.) that compare values and determine when one is greater than, less than, or equal to another. For user-defined types, we can override the behavior of the built-in operators by providing a method named __cmp__.

__cmp__ takes two parameters, self and other, and returns a positive number if the first object is greater, a negative number if the second object is greater, and 0 if they are equal to each other.



The correct ordering for cards is not obvious. For example, which is better, the 3 of Clubs or the 2 of Diamonds? One has a higher rank, but the other has a higher suit. In order to compare cards, you have to decide whether rank or suit is more important.

The answer might depend on what game you are playing, but to keep things simple, we’ll make the arbitrary choice that suit is more important, so all of the Spades outrank all of the Diamonds, and so on.



With that decided, we can write __cmp__:

# inside class Card:

    def __cmp__(self, other):
        # check the suits
        if self.suit > other.suit: return 1
        if self.suit < other.suit: return -1

        # suits are the same... check ranks
        if self.rank > other.rank: return 1
        if self.rank < other.rank: return -1

        # ranks are the same... it's a tie
        return 0    

You can write this more concisely using tuple comparison:


# inside class Card:

    def __cmp__(self, other):
        t1 = self.suit, self.rank
        t2 = other.suit, other.rank
        return cmp(t1, t2)

The built-in function cmp has the same interface as the method __cmp__: it takes two values and returns a positive number if the first is larger, a negative number of the second is larger, and 0 if they are equal.


Exercise 1  

Write a __cmp__ method for Time objects. Hint: you can use tuple comparison, but you also might consider using

integer subtraction.

18.4  Decks

Now that we have Cards, the next step is to define Decks. Since a deck is made up of cards, it is natural for each Deck to contain a list of cards as an attribute.



The following is a class definition for Deck. The init method creates the attribute cards and generates the standard set of fifty-two cards:




class Deck:

    def __init__(self):
        self.cards = []
        for suit in range(4):
            for rank in range(1, 14):
                card = Card(suit, rank)
                self.cards.append(card)

The easiest way to populate the deck is with a nested loop. The outer loop enumerates the suits from 0 to 3. The inner loop enumerates the ranks from 1 to 13. Each iteration creates a new Card with the current suit and rank, and appends it to self.cards.

18.5  Printing the deck

Here is a __str__ method for Deck:

#inside class Deck:

    def __str__(self):
        res = []
        for card in self.cards:
            res.append(str(card))
        return '\n'.join(res)

This method demonstrates an efficient way to accumulate a large string: building a list of strings and then using join. The built-in function str invokes the __str__ method on each card and returns the string representation.




Since we invoke join on a newline character, the cards are separated by newlines. Here’s what the result looks like:

>>> deck = Deck()
>>> print deck
Ace of Clubs
2 of Clubs
3 of Clubs
...
10 of Spades
Jack of Spades
Queen of Spades
King of Spades

Even though the result appears on 52 lines, it is one long string that contains newlines.

18.6  Add, remove, shuffle and sort

To deal cards, we would like a method that removes a card from the deck and returns it. The list method pop provides a convenient way to do that:


#inside class Deck:

    def pop_card(self):
        return self.cards.pop()

Since pop removes the last card in the list, we are dealing from the bottom of the deck. In real life bottom dealing is frowned upon1, but in this context it’s ok.



To add a card, we can use the list method append:

#inside class Deck:

    def add_card(self, card):
        self.cards.append(card)

A method like this that uses another function without doing much real work is sometimes called a veneer. The metaphor comes from woodworking, where it is common to glue a thin layer of good quality wood to the surface of a cheaper piece of wood.

In this case we are defining a “thin” method that expresses a list operation in terms that are appropriate for decks.

As another example, we can write a Deck method named shuffle using the function shuffle from the random module:



# inside class Deck:
            
    def shuffle(self):
        random.shuffle(self.cards)

Don’t forget to import random.

Exercise 2  

' Write a Deck method named 'sort' that uses the list method 'sort' to sort the cards in a 'Deck'. 'sort' uses the __cmp__ method we defined to determine sort order.

18.7  Inheritance

The language feature most often associated with object-oriented programming is inheritance. Inheritance is the ability to define a new class that is a modified version of an existing class.




It is called “inheritance” because the new class inherits the methods of the existing class. Extending this metaphor, the existing class is called the parent and the new class is called the child.

As an example, let’s say we want a class to represent a “hand,” that is, the set of cards held by one player. A hand is similar to a deck: both are made up of a set of cards, and both require operations like adding and removing cards.

A hand is also different from a deck; there are operations we want for hands that don’t make sense for a deck. For example, in poker we might compare two hands to see which one wins. In bridge, we might compute a score for a hand in order to make a bid.

This relationship between classes—similar, but different—lends itself to inheritance.

The definition of a child class is like other class definitions, but the name of the parent class appears in parentheses:




class Hand(Deck):
    """represents a hand of playing cards"""

This definition indicates that Hand inherits from Deck; that means we can use methods like pop_card and add_card for Hands as well as Decks.

Hand also inherits __init__ from Deck, but it doesn’t really do what we want: instead of populating the hand with 52 new cards, the init method for Hands should initialize cards with an empty list.



If we provide an init method in the Hand class, it overrides the one in the Deck class:

# inside class Hand:

    def __init__(self, label=''):
        self.cards = []
        self.label = label

So when you create a Hand, Python invokes this init method:

>>> hand = Hand('new hand')
>>> print hand.cards
[]
>>> print hand.label
new hand

But the other methods are inherited from Deck, so we can use pop_card and add_card to deal a card:

>>> deck = Deck()
>>> card = deck.pop_card()
>>> hand.add_card(card)
>>> print hand
King of Spades

A natural next step is to encapsulate this code in a method called move_cards:

#inside class Deck:

    def move_cards(self, hand, num):
        for i in range(num):
            hand.add_card(self.pop_card())

move_cards takes two arguments, a Hand object and the number of cards to deal. It modifies both self and hand, and returns None.

In some games, cards are moved from one hand to another, or from a hand back to the deck. You can use move_cards for any of these operations: self can be either a Deck or a Hand, and hand, despite the name, can also be a Deck.

Exercise 3  

Write a Deck method called deal_hands that takes two parameters, the number of hands and the number of cards per hand, and that creates new Hand objects, deals the appropriate number of cards per hand, and returns a list of Hand objects.

Inheritance is a useful feature. Some programs that would be repetitive without inheritance can be written more elegantly with it. Inheritance can facilitate code reuse, since you can customize the behavior of parent classes without having to modify them. In some cases, the inheritance structure reflects the natural structure of the problem, which makes the program easier to understand.

On the other hand, inheritance can make programs difficult to read. When a method is invoked, it is sometimes not clear where to find its definition. The relevant code may be scattered among several modules. Also, many of the things that can be done using inheritance can be done as well or better without it.

18.8  Class diagrams

So far we have seen stack diagrams, which show the state of a program, and object diagrams, which show the attributes of an object and their values. These diagrams represent a snapshot in the execution of a program, so they change as the program runs.

They are also highly detailed; for some purposes, too detailed. A class diagrams is a more abstract representation of the structure of a program. Instead of showing individual objects, it shows classes and the relationships between them.

There are several kinds of relationship between classes:

  • Objects in one class might contain references to objects

in another class. For example, each Rectangle contains a reference to a Point, and each Deck contains references to many Cards. This kind of relationship is called HAS-A, as in, “a Rectangle has a Point.”

  • One class might inherit from another. This relationship

is called IS-A, as in, “a Hand is a kind of a Deck.”

  • One class might depend on another in the sense that changes

in one class would require changes in the other.




A class diagram is a graphical representation of these relationships2. For example, this diagram shows the relationships between Card, Deck and Hand.

<IMG SRC="book027.png">

The arrow with a hollow triangle head represents an IS-A relationship; in this case it indicates that Hand inherits from Deck.

The standard arrow head represents a HAS-A relationship; in this case a Deck has references to Card objects.

The star (*) near the arrow head is a multiplicity; it indicates how many Cards a Deck has. A multiplicity can be a simple number, like 52, a range, like 5..7 or a star, which indicates that a Deck can have any number of Cards.

A more detailed diagram might show that a Deck actually contains a list of Cards, but built-in types like list and dict are usually not included in class diagrams.

Exercise 4  

Read 'TurtleWorld.py', 'World.py' and 'Gui.py' and draw a class diagram that shows the relationships among the classes defined there.

=== 18.9  Debugging ===



Inheritance can make debugging a challenge because when you invoke a method on an object, you might not know which method will be invoked.

Suppose you are writing a function that works with Hand objects. You would like it to work with all kinds of Hands, like PokerHands, BridgeHands, etc. If you invoke a method like shuffle, you might get the one defined in Deck, but if any of the subclasses override this method, you’ll get that version instead.

Any time you are unsure about the flow of execution through your program, the simplest solution is to add print statements at the beginning of the relevant methods. If Deck.shuffle prints a message that says something like Running Deck.shuffle, then as the program runs it traces the flow of execution.

As an alternative, you could use this function, which takes an object and a method name (as a string) and returns the class that provides the definition of the method:

def find_defining_class(obj, meth_name):
    for ty in type(obj).mro():
        if meth_name in ty.__dict__:
            return ty

Here’s an example:

>>> hand = Hand()
>>> print find_defining_class(hand, 'shuffle')
<class 'Card.Deck'>

So the shuffle method for this Hand is the one in Deck.



find_defining_class uses the mro method to get the list of class objects (types) that will be searched for methods. “MRO” stands for “method resolution order.”




Here’s a program design suggestion: whenever you override a method, the interface of the new method should be the same as the old. It should take the same parameters, return the same type, and obey the same preconditions and postconditions. If you obey this rule, you will find that any function designed to work with an instance of a superclass, like a Deck, will also work with instances of subclasses like a Hand or PokerHand.

If you violate this rule, your code will collapse like (sorry) a house of cards.

18.10  Glossary

encode:
To represent one set of values using another set of values by constructing a mapping between them.
class attribute:
An attribute associated with a class object. Class attributes are defined inside a class definition but outside any method.
instance attribute:
An attribute associated with an instance of a class.
veneer:
A method or function that provides a different interface to another function without doing much computation.
inheritance:
The ability to define a new class that is a modified version of a previously defined class.
parent class:
The class from which a child class inherits.
child class:
A new class created by inheriting from an existing class; also called a “subclass.”
IS-A relationship:
The relationship between a child class and its parent class.
HAS-A relationship:
The relationship between two classes where instances of one class contain references to instances of the other.
class diagram:
A diagram that shows the classes in a program and the relationships between them.
multiplicity:
A notation in a class diagram that shows, for a HAS-A relationship, how many references there are to instances of another class.

=== 18.11  Exercises ===

Exercise 5  

The following are the possible hands in poker, in increasing order of value (and decreasing order of probability):

pair:
two cards with the same rank
''two pair:''
two pairs of cards with the same rank
''three of a kind:''
three cards with the same rank
''straight:''
five cards with ranks in sequence (aces can be high or low, so 'Ace-2-3-4-5' is a straight and so is '10-Jack-Queen-King-Ace', but 'Queen-King-Ace-2-3' is not.)
''flush:''
five cards with the same suit
''full house:''
three cards with one rank, two cards with another
''four of a kind:''
four cards with the same rank
''straight flush:''
five cards in sequence (as defined above) and with the same suit

The goal of these exercises is to estimate the probability of drawing these various hands.

  • Download the following files from 'thinkpython.com/code':
    Card.py
    : A complete version of the 'Card',
'Deck' and 'Hand' classes in this chapter.
''PokerHand.py''
: An incomplete implementation of a class that represents a poker hand, and some code that tests it.
  • 'If you run '''PokerHand.py''', it deals six 7-card poker hands

and checks to see if any of them contains a flush. Read this code carefully before you go on.'

  • 'Add methods to '''PokerHand.py''' named ''has_pair'',

''has_twopair'', etc. that return True or False according to whether or not the hand meets the relevant criteria. Your code should work correctly for “hands” that contain any number of cards (although 5 and 7 are the most common sizes).'

  • 'Write a method named '''classify''' that figures out

the highest-value classification for a hand and sets the '''label''' attribute accordingly. For example, a 7-card hand might contain a flush and a pair; it should be labeled “flush”.'

  • 'When you are convinced that your classification methods are

working, the next step is to estimate the probabilities of the various hands. Write a function in '''PokerHand.py''' that shuffles a deck of cards, divides it into hands, classifies the hands, and counts the number of times various classifications appear.'

  • 'Print a table of the classifications and their probabilities.

Run your program with larger and larger numbers of hands until the output values converge to a reasonable degree of accuracy. Compare your results to the values at '''wikipedia.org/wiki/Hand_rankings'''.'

Exercise 6  

This exercise uses TurtleWorld from Chapter '4'. You will write code that makes Turtles play tag. If you are not familiar with the rules of tag, see 'wikipedia.org/wiki/Tag_(game)'.

  • Download 'thinkpython.com/code/Wobbler.py' and run it. You

should see a TurtleWorld with three Turtles. If you press the 'Run' button, the Turtles wander at random.

  • Read the code and make sure you understand how it works.

The 'Wobbler' class inherits from 'Turtle', which means that the 'Turtle' methods 'lt', 'rt', 'fd' and 'bk' work on Wobblers. The 'step' method gets invoked by TurtleWorld. It invokes 'steer', which turns the Turtle in the desired direction, 'wobble', which makes a random turn in proportion to the Turtle’s clumsiness, and 'move', which moves forward a few pixels, depending on the Turtle’s speed.

  • Create a file named 'Tagger.py'. Import everything from

'Wobbler', then define a class named 'Tagger' that inherits from 'Wobbler'. Call make_world passing the 'Tagger' class object as an argument.

  • Add a 'steer' method to 'Tagger' to override the one in

'Wobbler'. As a starting place, write a version that always points the Turtle toward the origin. Hint: use the math function 'atan2' and the Turtle attributes 'x', 'y' and 'heading'.

  • Modify 'steer' so that the Turtles stay in bounds.

For debugging, you might want to use the 'Step' button, which invokes 'step' once on each Turtle.

  • Modify 'steer' so that each Turtle points toward its nearest

neighbor. Hint: Turtles have an attribute, 'world', that is a reference to the TurtleWorld they live in, and the TurtleWorld has an attribute, 'animals', that is a list of all Turtles in the world.

  • Modify 'steer' so the Turtles play tag. You can add methods

to 'Tagger' and you can override 'steer' and __init__, but you may not modify or override 'step', 'wobble' or 'move'. Also, 'steer' is allowed to change the heading of the Turtle but not the position. Adjust the rules and your 'steer' method for good quality play; for example, it should be possible for the slow Turtle to tag the faster Turtles eventually.

You can get my solution from 'thinkpython.com/code/Tagger.py'.


1
See wikipedia.org/wiki/Bottom_dealing.
2
The diagrams I am using here are similar to UML (see wikipedia.org/wiki/Unified_Modeling_Language), with a few simplifications.

<IMG SRC="previous_motif.gif" ALT="Previous"> <IMG SRC="contents_motif.gif" ALT="Up"> <IMG SRC="next_motif.gif" ALT="Next">