Jump to content

Archive:Think Python/Classes and objects: 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>Whiteknight
m Partial (mostly) conversion from HTML to Wikitext
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;15&#XA0;&#XA0;Classes and objects ==
<META name="GENERATOR" content="hevea 1.10">
 
<LINK rel="stylesheet" type="text/css" href="book.css">
=== 15.1&#XA0;&#XA0;User-defined types ===
<TITLE>Classes and objects</TITLE>
 
</HEAD>
 
<BODY >
 
<A HREF="book015.html"><IMG SRC="previous_motif.gif" ALT="Previous"></A>
 
<A HREF="index.html"><IMG SRC="contents_motif.gif" ALT="Up"></A>
 
<A HREF="book017.html"><IMG SRC="next_motif.gif" ALT="Next"></A>
 
<HR>
 
<H1 CLASS="chapter"><A NAME="htoc181"><FONT COLOR=black><FONT SIZE=3>Chapter&#XA0;15</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;Classes and objects</FONT></FONT></H1><H2 CLASS="section"><A NAME="toc165"></A><A NAME="htoc182"><FONT COLOR=black><FONT SIZE=3>15.1</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;User-defined types</FONT></FONT></H2><P><FONT COLOR=black><FONT SIZE=3>
We have used many of Python&#X2019;s built-in types; now we are going
</FONT></FONT><A NAME="point"></A></P><P><A NAME="@default1352"></A><FONT COLOR=black><FONT SIZE=3>
</FONT></FONT><A NAME="@default1353"></A></P><P><FONT COLOR=black><FONT SIZE=3>We have used many of Python&#X2019;s built-in types; now we are going
to define a new type. As an example, we will create a type
to define a new type. As an example, we will create a type
called </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Point</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> that represents a point in two-dimensional
called <TT>Point</TT> that represents a point in two-dimensional
space.</FONT></FONT></P><P><A NAME="@default1354"></A></P><P><FONT COLOR=black><FONT SIZE=3>In mathematical notation, points are often written in
space.
 
In mathematical notation, points are often written in
parentheses with a comma separating the coordinates. For example,
parentheses with a comma separating the coordinates. For example,
</FONT></FONT><FONT COLOR=black><FONT SIZE=3>(0, 0)</FONT></FONT><FONT COLOR=black><FONT SIZE=3> represents the origin, and </FONT></FONT><FONT COLOR=black><FONT SIZE=3>(<I>x</I>, <I>y</I>)</FONT></FONT><FONT COLOR=black><FONT SIZE=3> represents the
(0, 0) represents the origin, and (<I>x</I>, <I>y</I>) represents the
point </FONT></FONT><FONT COLOR=black><FONT SIZE=3><I>x</I></FONT></FONT><FONT COLOR=black><FONT SIZE=3> units to the right and </FONT></FONT><FONT COLOR=black><FONT SIZE=3><I>y</I></FONT></FONT><FONT COLOR=black><FONT SIZE=3> units up from the origin.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>There are several ways we might represent points in Python:</FONT></FONT></P><UL CLASS="itemize"><LI CLASS="li-itemize"><FONT COLOR=black><FONT SIZE=3>We could store the coordinates separately in two
point <I>x</I> units to the right and <I>y</I> units up from the origin.
variables, </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>x</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> and </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>y</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.</FONT></FONT></LI><LI CLASS="li-itemize"><FONT COLOR=black><FONT SIZE=3>We could store the coordinates as elements in a list
 
or tuple.</FONT></FONT></LI><LI CLASS="li-itemize"><FONT COLOR=black><FONT SIZE=3>We could create a new type to represent points as
There are several ways we might represent points in Python:
objects.</FONT></FONT></LI></UL><P><A NAME="@default1355"></A></P><P><FONT COLOR=black><FONT SIZE=3>Creating a new type
 
*We could store the coordinates separately in two
variables, <TT>x</TT> and <TT>y</TT>.
 
*We could store the coordinates as elements in a list
or tuple.
 
*We could create a new type to represent points as
objects.
 
Creating a new type
is (a little) more complicated than the other options, but
is (a little) more complicated than the other options, but
it has advantages that will be apparent soon.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>A user-defined type is also called a </FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>class</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.
it has advantages that will be apparent soon.
A class definition looks like this:</FONT></FONT></P><P><A NAME="@default1356"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1357"></A><FONT COLOR=black><FONT SIZE=3>
A user-defined type is also called a '''class'''.
</FONT></FONT><A NAME="@default1358"></A><FONT COLOR=black><FONT SIZE=3>
A class definition looks like this:
</FONT></FONT><A NAME="@default1359"></A></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>class Point(object):
 
 
 
 
 
<PRE CLASS="verbatim">class Point(object):
     """represents a point in 2-D space"""
     """represents a point in 2-D space"""
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>This header indicates that the new class is a </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Point</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>,
</PRE>
which is a kind of </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>object</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, which is a built-in
This header indicates that the new class is a <TT>Point</TT>,
type.</FONT></FONT></P><P><A NAME="@default1360"></A><FONT COLOR=black><FONT SIZE=3>
which is a kind of <TT>object</TT>, which is a built-in
</FONT></FONT><A NAME="@default1361"></A></P><P><FONT COLOR=black><FONT SIZE=3>The body is a docstring that explains what the class is for.
type.
 
 
 
 
The body is a docstring that explains what the class is for.
You can define variables and functions inside a class definition,
You can define variables and functions inside a class definition,
but we will get back to that later.</FONT></FONT></P><P><A NAME="@default1362"></A></P><P><FONT COLOR=black><FONT SIZE=3>Defining a class named </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Point</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> creates a class object.</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>&gt;&gt;&gt; print Point
but we will get back to that later.
 
Defining a class named <TT>Point</TT> creates a class object.
<PRE CLASS="verbatim">&gt;&gt;&gt; print Point
&lt;class '__main__.Point'&gt;
&lt;class '__main__.Point'&gt;
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>Because </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Point</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> is defined at the top level, its &#X201C;full
</PRE>
name&#X201D; is </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>__main__.Point</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>.</FONT></FONT></P><P><A NAME="@default1363"></A><FONT COLOR=black><FONT SIZE=3>
Because <TT>Point</TT> is defined at the top level, its &#X201C;full
</FONT></FONT><A NAME="@default1364"></A></P><P><FONT COLOR=black><FONT SIZE=3>The class object is like a factory for creating objects. To create a
name&#X201D; is <CODE>__main__.Point</CODE>.
Point, you call </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Point</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> as if it were a function.</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>&gt;&gt;&gt; blank = Point()
 
 
 
 
The class object is like a factory for creating objects. To create a
Point, you call <TT>Point</TT> as if it were a function.
<PRE CLASS="verbatim">&gt;&gt;&gt; blank = Point()
&gt;&gt;&gt; print blank
&gt;&gt;&gt; print blank
&lt;__main__.Point instance at 0xb7e9d3ac&gt;
&lt;__main__.Point instance at 0xb7e9d3ac&gt;
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>The return value is a reference to a Point object, which we
</PRE>
assign to </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>blank</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.  
The return value is a reference to a Point object, which we
assign to <TT>blank</TT>.  
Creating a new object is called
Creating a new object is called
</FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>instantiation</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, and the object is an </FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>instance</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3> of
'''instantiation''', and the object is an '''instance''' of
the class.</FONT></FONT></P><P><A NAME="@default1365"></A><FONT COLOR=black><FONT SIZE=3>
the class.
</FONT></FONT><A NAME="@default1366"></A></P><P><FONT COLOR=black><FONT SIZE=3>When you print an instance, Python tells you what class it
 
 
 
 
When you print an instance, Python tells you what class it
belongs to and where it is stored in memory (the prefix
belongs to and where it is stored in memory (the prefix
</FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>0x</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> means that the following number is in hexadecimal).</FONT></FONT></P><P><A NAME="@default1367"></A></P><H2 CLASS="section"><A NAME="toc166"></A><A NAME="htoc183"><FONT COLOR=black><FONT SIZE=3>15.2</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;Attributes</FONT></FONT></H2><P><A NAME="@default1368"></A><FONT COLOR=black><FONT SIZE=3>
<TT>0x</TT> means that the following number is in hexadecimal).
</FONT></FONT><A NAME="@default1369"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1370"></A></P><P><FONT COLOR=black><FONT SIZE=3>You can assign values to an instance using dot notation:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>&gt;&gt;&gt; blank.x = 3.0
=== 15.2&#XA0;&#XA0;Attributes ===
 
 
 
 
 
You can assign values to an instance using dot notation:
<PRE CLASS="verbatim">&gt;&gt;&gt; blank.x = 3.0
&gt;&gt;&gt; blank.y = 4.0
&gt;&gt;&gt; blank.y = 4.0
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>This syntax is similar to the syntax for selecting a variable from a
</PRE>
module, such as </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>math.pi</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> or </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>string.whitespace</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>. In this case,
This syntax is similar to the syntax for selecting a variable from a
module, such as <TT>math.pi</TT> or <TT>string.whitespace</TT>. In this case,
though, we are assigning values to named elements of an object.
though, we are assigning values to named elements of an object.
These elements are called </FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>attributes</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>As a noun, &#X201C;AT-trib-ute&#X201D; is pronounced with emphasis on the first
These elements are called '''attributes'''.
syllable, as opposed to &#X201C;a-TRIB-ute,&#X201D; which is a verb.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>The following diagram shows the result of these assignments.
 
As a noun, &#X201C;AT-trib-ute&#X201D; is pronounced with emphasis on the first
syllable, as opposed to &#X201C;a-TRIB-ute,&#X201D; which is a verb.
 
The following diagram shows the result of these assignments.
A state diagram that shows an object and its attributes is
A state diagram that shows an object and its attributes is
called an </FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>object diagram</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>:</FONT></FONT></P><P><A NAME="@default1371"></A><FONT COLOR=black><FONT SIZE=3>
called an '''object diagram''':
</FONT></FONT><A NAME="@default1372"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1373"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1374"></A></P><DIV CLASS="center"><FONT COLOR=black><FONT SIZE=3><IMG SRC="book022.png"></FONT></FONT></DIV><P><FONT COLOR=black><FONT SIZE=3>The variable </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>blank</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> refers to a Point object, which
 
 
 
<DIV CLASS="center"><IMG SRC="book022.png"></DIV>
The variable <TT>blank</TT> refers to a Point object, which
contains two attributes. Each attribute refers to a
contains two attributes. Each attribute refers to a
floating-point number.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>You can read the value of an attribute using the same syntax:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>&gt;&gt;&gt; print blank.y
floating-point number.
 
You can read the value of an attribute using the same syntax:
<PRE CLASS="verbatim">&gt;&gt;&gt; print blank.y
4.0
4.0
&gt;&gt;&gt; x = blank.x
&gt;&gt;&gt; x = blank.x
&gt;&gt;&gt; print x
&gt;&gt;&gt; print x
3.0
3.0
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>The expression </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>blank.x</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> means, &#X201C;Go to the object </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>blank</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>
</PRE>
refers to and get the value of </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>x</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.&#X201D; In this case, we assign that
The expression <TT>blank.x</TT> means, &#X201C;Go to the object <TT>blank</TT>
value to a variable named </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>x</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>. There is no conflict between
refers to and get the value of <TT>x</TT>.&#X201D; In this case, we assign that
the variable </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>x</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> and the attribute </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>x</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>You can use dot notation as part of any expression. For example:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>&gt;&gt;&gt; print '(%g, %g)' % (blank.x, blank.y)
value to a variable named <TT>x</TT>. There is no conflict between
the variable <TT>x</TT> and the attribute <TT>x</TT>.
 
You can use dot notation as part of any expression. For example:
<PRE CLASS="verbatim">&gt;&gt;&gt; print '(%g, %g)' % (blank.x, blank.y)
(3.0, 4.0)
(3.0, 4.0)
&gt;&gt;&gt; distance = math.sqrt(blank.x**2 + blank.y**2)
&gt;&gt;&gt; distance = math.sqrt(blank.x**2 + blank.y**2)
&gt;&gt;&gt; print distance
&gt;&gt;&gt; print distance
5.0
5.0
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>You can pass an instance as an argument in the usual way.
</PRE>
For example:</FONT></FONT></P><P><A NAME="@default1375"></A></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>def print_point(p):
You can pass an instance as an argument in the usual way.
For example:
 
<PRE CLASS="verbatim">def print_point(p):
     print '(%g, %g)' % (p.x, p.y)
     print '(%g, %g)' % (p.x, p.y)
</FONT></FONT></PRE><P><CODE><FONT COLOR=black><FONT SIZE=3>print_point</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> takes a point as an argument and displays it in
</PRE>
mathematical notation. To invoke it, you can pass </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>blank</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> as
<CODE>print_point</CODE> takes a point as an argument and displays it in
an argument:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>&gt;&gt;&gt; print_point(blank)
mathematical notation. To invoke it, you can pass <TT>blank</TT> as
an argument:
<PRE CLASS="verbatim">&gt;&gt;&gt; print_point(blank)
(3.0, 4.0)
(3.0, 4.0)
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>Inside the function, </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>p</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> is an alias for </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>blank</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, so if
</PRE>
the function modifies </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>p</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>blank</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> changes.</FONT></FONT></P><P><A NAME="@default1376"></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>
Inside the function, <TT>p</TT> is an alias for <TT>blank</TT>, so if
Write a function called </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>distance</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> that it takes two Points
the function modifies <TT>p</TT>, <TT>blank</TT> changes.
 
<DIV CLASS="theorem">'''Exercise&#XA0;1'''&#XA0;&#XA0;''
Write a function called ''''<TT>distance</TT>'''' that it takes two Points
as arguments and returns the distance between them.
as arguments and returns the distance between them.
</EM></FONT></FONT></DIV><H2 CLASS="section"><A NAME="toc167"></A><A NAME="htoc184"><FONT COLOR=black><FONT SIZE=3>15.3</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;Rectangles</FONT></FONT></H2><P><FONT COLOR=black><FONT SIZE=3>Sometimes it is obvious what the attributes of an object should be,
''</DIV>=== 15.3&#XA0;&#XA0;Rectangles ===
 
Sometimes it is obvious what the attributes of an object should be,
but other times you have to make decisions. For example, imagine you
but other times you have to make decisions. For example, imagine you
are designing a class to represent rectangles. What attributes would
are designing a class to represent rectangles. What attributes would
you use to specify the location and size of a rectangle? You can
you use to specify the location and size of a rectangle? You can
ignore angle; to keep things simple, assume that the rectangle is
ignore angle; to keep things simple, assume that the rectangle is
either vertical or horizontal.</FONT></FONT></P><P><A NAME="@default1377"></A></P><P><FONT COLOR=black><FONT SIZE=3>There are at least two possibilities: </FONT></FONT></P><UL CLASS="itemize"><LI CLASS="li-itemize"><FONT COLOR=black><FONT SIZE=3>You could specify one corner of the rectangle
either vertical or horizontal.
(or the center), the width, and the height.</FONT></FONT></LI><LI CLASS="li-itemize"><FONT COLOR=black><FONT SIZE=3>You could specify two opposing corners.</FONT></FONT></LI></UL><P><FONT COLOR=black><FONT SIZE=3>At this point it is hard to say whether either is better than
 
the other, so we&#X2019;ll implement the first one, just as an example.</FONT></FONT></P><P><A NAME="@default1378"></A><FONT COLOR=black><FONT SIZE=3>
There are at least two possibilities:  
</FONT></FONT><A NAME="@default1379"></A></P><P><FONT COLOR=black><FONT SIZE=3>Here is the class definition:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>class Rectangle(object):
 
*You could specify one corner of the rectangle
(or the center), the width, and the height.
 
*You could specify two opposing corners.
 
At this point it is hard to say whether either is better than
the other, so we&#X2019;ll implement the first one, just as an example.
 
 
 
 
Here is the class definition:
<PRE CLASS="verbatim">class Rectangle(object):
     """represent a rectangle.  
     """represent a rectangle.  
       attributes: width, height, corner.
       attributes: width, height, corner.
     """
     """
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>The docstring lists the attributes: </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>width</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> and
</PRE>
</FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>height</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> are numbers; </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>corner</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> is a Point object that
The docstring lists the attributes: <TT>width</TT> and
specifies the lower-left corner.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>To represent a rectangle, you have to instantiate a Rectangle
<TT>height</TT> are numbers; <TT>corner</TT> is a Point object that
object and assign values to the attributes:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>box = Rectangle()
specifies the lower-left corner.
 
To represent a rectangle, you have to instantiate a Rectangle
object and assign values to the attributes:
<PRE CLASS="verbatim">box = Rectangle()
box.width = 100.0
box.width = 100.0
box.height = 200.0
box.height = 200.0
Line 113: Line 194:
box.corner.x = 0.0
box.corner.x = 0.0
box.corner.y = 0.0
box.corner.y = 0.0
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>The expression </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>box.corner.x</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> means,
</PRE>
&#X201C;Go to the object </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>box</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> refers to and select the attribute named
The expression <TT>box.corner.x</TT> means,
</FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>corner</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>; then go to that object and select the attribute named
&#X201C;Go to the object <TT>box</TT> refers to and select the attribute named
</FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>x</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.&#X201D;</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>The figure shows the state of this object:</FONT></FONT></P><P><A NAME="@default1380"></A><FONT COLOR=black><FONT SIZE=3>
<TT>corner</TT>; then go to that object and select the attribute named
</FONT></FONT><A NAME="@default1381"></A><FONT COLOR=black><FONT SIZE=3>
<TT>x</TT>.&#X201D;
</FONT></FONT><A NAME="@default1382"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1383"></A></P><DIV CLASS="center"><FONT COLOR=black><FONT SIZE=3><IMG SRC="book023.png"></FONT></FONT></DIV><P><FONT COLOR=black><FONT SIZE=3>An object that is an attribute of another object is </FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>embedded</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.</FONT></FONT></P><P><A NAME="@default1384"></A><FONT COLOR=black><FONT SIZE=3>
The figure shows the state of this object:
</FONT></FONT><A NAME="@default1385"></A></P><H2 CLASS="section"><A NAME="toc168"></A><A NAME="htoc185"><FONT COLOR=black><FONT SIZE=3>15.4</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;Instances as return values</FONT></FONT></H2><P><A NAME="@default1386"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1387"></A></P><P><FONT COLOR=black><FONT SIZE=3>Functions can return instances. For example, </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>find_center</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>
 
takes a </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Rectangle</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> as an argument and returns a </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Point</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>
 
that contains the coordinates of the center of the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Rectangle</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>def find_center(box):
 
 
<DIV CLASS="center"><IMG SRC="book023.png"></DIV>
An object that is an attribute of another object is '''embedded'''.
 
 
 
=== 15.4&#XA0;&#XA0;Instances as return values ===
 
 
 
 
Functions can return instances. For example, <CODE>find_center</CODE>
takes a <TT>Rectangle</TT> as an argument and returns a <TT>Point</TT>
that contains the coordinates of the center of the <TT>Rectangle</TT>:
<PRE CLASS="verbatim">def find_center(box):
     p = Point()
     p = Point()
     p.x = box.corner.x + box.width/2.0
     p.x = box.corner.x + box.width/2.0
     p.y = box.corner.y + box.height/2.0
     p.y = box.corner.y + box.height/2.0
     return p
     return p
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>Here is an example that passes </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>box</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> as an argument and assigns
</PRE>
the resulting Point to </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>center</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>&gt;&gt;&gt; center = find_center(box)
Here is an example that passes <TT>box</TT> as an argument and assigns
the resulting Point to <TT>center</TT>:
<PRE CLASS="verbatim">&gt;&gt;&gt; center = find_center(box)
&gt;&gt;&gt; print_point(center)
&gt;&gt;&gt; print_point(center)
(50.0, 100.0)
(50.0, 100.0)
</FONT></FONT></PRE><H2 CLASS="section"><A NAME="toc169"></A><A NAME="htoc186"><FONT COLOR=black><FONT SIZE=3>15.5</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;Objects are mutable</FONT></FONT></H2><P><A NAME="@default1388"></A><FONT COLOR=black><FONT SIZE=3>
</PRE>=== 15.5&#XA0;&#XA0;Objects are mutable ===
</FONT></FONT><A NAME="@default1389"></A></P><P><FONT COLOR=black><FONT SIZE=3>You can change the state of an object by making an assignment to one of
 
 
 
 
You can change the state of an object by making an assignment to one of
its attributes. For example, to change the size of a rectangle
its attributes. For example, to change the size of a rectangle
without changing its position, you can modify the values of </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>width</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> and </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>height</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>box.width = box.width + 50
without changing its position, you can modify the values of <TT>width</TT> and <TT>height</TT>:
<PRE CLASS="verbatim">box.width = box.width + 50
box.height = box.width + 100
box.height = box.width + 100
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>You can also write functions that modify objects. For example,
</PRE>
</FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>grow_rectangle</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> takes a Rectangle object and two numbers,
You can also write functions that modify objects. For example,
</FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>dwidth</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> and </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>dheight</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, and adds the numbers to the
<CODE>grow_rectangle</CODE> takes a Rectangle object and two numbers,
width and height of the rectangle:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>def grow_rectangle(rect, dwidth, dheight) :
<TT>dwidth</TT> and <TT>dheight</TT>, and adds the numbers to the
width and height of the rectangle:
<PRE CLASS="verbatim">def grow_rectangle(rect, dwidth, dheight) :
     rect.width += dwidth
     rect.width += dwidth
     rect.height += dheight
     rect.height += dheight
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>Here is an example that demonstrates the effect:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>&gt;&gt;&gt; print box.width
</PRE>
Here is an example that demonstrates the effect:
<PRE CLASS="verbatim">&gt;&gt;&gt; print box.width
100.0
100.0
&gt;&gt;&gt; print box.height
&gt;&gt;&gt; print box.height
Line 152: Line 259:
&gt;&gt;&gt; print box.height
&gt;&gt;&gt; print box.height
300.0
300.0
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>Inside the function, </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>rect</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> is an
</PRE>
alias for </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>box</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, so if the function modifies </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>rect</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>,  
Inside the function, <TT>rect</TT> is an
</FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>box</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> changes.</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>
alias for <TT>box</TT>, so if the function modifies <TT>rect</TT>,  
Write a function named </EM></FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3><EM>move_rectangle</EM></FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3><EM> that takes
<TT>box</TT> changes.
a Rectangle and two numbers named </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>dx</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> and </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>dy</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>. It
<DIV CLASS="theorem">'''Exercise&#XA0;2'''&#XA0;&#XA0;''
should change the location of the rectangle by adding </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>dx</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>
Write a function named ''<CODE>''move_rectangle''</CODE>'' that takes
to the </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>x</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> coordinate of </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>corner</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> and adding </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>dy</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>
a Rectangle and two numbers named ''''<TT>dx</TT>'''' and ''''<TT>dy</TT>''''. It
to the </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>y</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> coordinate of </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>corner</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>.
should change the location of the rectangle by adding ''''<TT>dx</TT>''''
</EM></FONT></FONT></DIV><H2 CLASS="section"><A NAME="toc170"></A><A NAME="htoc187"><FONT COLOR=black><FONT SIZE=3>15.6</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;Copying</FONT></FONT></H2><P><A NAME="@default1390"></A></P><P><FONT COLOR=black><FONT SIZE=3>Aliasing can make a program difficult to read because changes
to the ''''<TT>x</TT>'''' coordinate of ''''<TT>corner</TT>'''' and adding ''''<TT>dy</TT>''''
to the ''''<TT>y</TT>'''' coordinate of ''''<TT>corner</TT>''''.
''</DIV>=== 15.6&#XA0;&#XA0;Copying ===
 
Aliasing can make a program difficult to read because changes
in one place might have unexpected effects in another place.
in one place might have unexpected effects in another place.
It is hard to keep track of all the variables that might refer
It is hard to keep track of all the variables that might refer
to a given object.</FONT></FONT></P><P><A NAME="@default1391"></A><FONT COLOR=black><FONT SIZE=3>
to a given object.
</FONT></FONT><A NAME="@default1392"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1393"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1394"></A></P><P><FONT COLOR=black><FONT SIZE=3>Copying an object is often an alternative to aliasing.
 
The </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>copy</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> module contains a function called </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>copy</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> that
 
can duplicate any object:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>&gt;&gt;&gt; p1 = Point()
 
 
Copying an object is often an alternative to aliasing.
The <TT>copy</TT> module contains a function called <TT>copy</TT> that
can duplicate any object:
<PRE CLASS="verbatim">&gt;&gt;&gt; p1 = Point()
&gt;&gt;&gt; p1.x = 3.0
&gt;&gt;&gt; p1.x = 3.0
&gt;&gt;&gt; p1.y = 4.0
&gt;&gt;&gt; p1.y = 4.0
Line 174: Line 290:
&gt;&gt;&gt; import copy
&gt;&gt;&gt; import copy
&gt;&gt;&gt; p2 = copy.copy(p1)
&gt;&gt;&gt; p2 = copy.copy(p1)
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3><TT>p1</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> and </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>p2</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> contain the same data, but they are
</PRE>
not the same Point.</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>&gt;&gt;&gt; print_point(p1)
<TT>p1</TT> and <TT>p2</TT> contain the same data, but they are
not the same Point.
<PRE CLASS="verbatim">&gt;&gt;&gt; print_point(p1)
(3.0, 4.0)
(3.0, 4.0)
&gt;&gt;&gt; print_point(p2)
&gt;&gt;&gt; print_point(p2)
Line 183: Line 301:
&gt;&gt;&gt; p1 == p2
&gt;&gt;&gt; p1 == p2
False
False
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>The </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>is</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> operator indicates that </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>p1</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> and </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>p2</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> are not the
</PRE>
The <TT>is</TT> operator indicates that <TT>p1</TT> and <TT>p2</TT> are not the
same object, which is what we expected. But you might have expected
same object, which is what we expected. But you might have expected
</FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>==</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> to yield </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>True</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> because these points contain the same
<TT>==</TT> to yield <TT>True</TT> because these points contain the same
data. In that case, you will be disappointed to learn that for
data. In that case, you will be disappointed to learn that for
instances, the default behavior of the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>==</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> operator is the same
instances, the default behavior of the <TT>==</TT> operator is the same
as the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>is</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> operator; it checks object identity, not object
as the <TT>is</TT> operator; it checks object identity, not object
equivalence. This behavior can be changed&#X2014;we&#X2019;ll see how later.</FONT></FONT></P><P><A NAME="@default1395"></A><FONT COLOR=black><FONT SIZE=3>
equivalence. This behavior can be changed&#X2014;we&#X2019;ll see how later.
</FONT></FONT><A NAME="@default1396"></A></P><P><FONT COLOR=black><FONT SIZE=3>If you use </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>copy.copy</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> to duplicate a Rectangle, you will find
 
that it copies the Rectangle object but not the embedded Point.</FONT></FONT></P><P><A NAME="@default1397"></A></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>&gt;&gt;&gt; box2 = copy.copy(box)
 
 
 
If you use <TT>copy.copy</TT> to duplicate a Rectangle, you will find
that it copies the Rectangle object but not the embedded Point.
 
<PRE CLASS="verbatim">&gt;&gt;&gt; box2 = copy.copy(box)
&gt;&gt;&gt; box2 is box
&gt;&gt;&gt; box2 is box
False
False
&gt;&gt;&gt; box2.corner is box.corner
&gt;&gt;&gt; box2.corner is box.corner
True
True
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>Here is what the object diagram looks like:</FONT></FONT></P><P><A NAME="@default1398"></A><FONT COLOR=black><FONT SIZE=3>
</PRE>
</FONT></FONT><A NAME="@default1399"></A><FONT COLOR=black><FONT SIZE=3>
Here is what the object diagram looks like:
</FONT></FONT><A NAME="@default1400"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1401"></A></P><P><FONT COLOR=black><FONT SIZE=3><BR>
 
 
 
 
 
<BR>
 
 
<DIV CLASS="center"><IMG SRC="book024.png"></DIV>


</FONT></FONT></P><DIV CLASS="center"><FONT COLOR=black><FONT SIZE=3><IMG SRC="book024.png"></FONT></FONT></DIV><P><FONT COLOR=black><FONT SIZE=3>
<BR>
<BR>
</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>This operation is called a </FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>shallow copy</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3> because it copies the
 
object and any references it contains, but not the embedded objects.</FONT></FONT></P><P><A NAME="@default1402"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1403"></A></P><P><FONT COLOR=black><FONT SIZE=3>For most applications, this is not what you want. In this example,
This operation is called a '''shallow copy''' because it copies the
invoking </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>grow_rectangle</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> on one of the Rectangles would not
object and any references it contains, but not the embedded objects.
affect the other, but invoking </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>move_rectangle</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> on either would
 
affect both! This behavior is confusing and error-prone.</FONT></FONT></P><P><A NAME="@default1404"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1405"></A></P><P><FONT COLOR=black><FONT SIZE=3>Fortunately, the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>copy</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> module contains a method named </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>deepcopy</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> that copies not only the object but also  
 
the objects it refers to, and the objects </FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>they</EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3> refer to,
 
For most applications, this is not what you want. In this example,
invoking <CODE>grow_rectangle</CODE> on one of the Rectangles would not
affect the other, but invoking <CODE>move_rectangle</CODE> on either would
affect both! This behavior is confusing and error-prone.
 
 
 
 
Fortunately, the <TT>copy</TT> module contains a method named <TT>deepcopy</TT> that copies not only the object but also  
the objects it refers to, and the objects ''they'' refer to,
and so on.
and so on.
You will not be surprised to learn that this operation is
You will not be surprised to learn that this operation is
called a </FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>deep copy</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.</FONT></FONT></P><P><A NAME="@default1406"></A><FONT COLOR=black><FONT SIZE=3>
called a '''deep copy'''.
</FONT></FONT><A NAME="@default1407"></A></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>&gt;&gt;&gt; box3 = copy.deepcopy(box)
 
 
 
<PRE CLASS="verbatim">&gt;&gt;&gt; box3 = copy.deepcopy(box)
&gt;&gt;&gt; box3 is box
&gt;&gt;&gt; box3 is box
False
False
&gt;&gt;&gt; box3.corner is box.corner
&gt;&gt;&gt; box3.corner is box.corner
False
False
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3><TT>box3</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> and </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>box</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> are completely separate objects.</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>
</PRE>
Write a version of </EM></FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3><EM>move_rectangle</EM></FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3><EM> that creates and
<TT>box3</TT> and <TT>box</TT> are completely separate objects.
<DIV CLASS="theorem">'''Exercise&#XA0;3'''&#XA0;&#XA0;''
Write a version of ''<CODE>''move_rectangle''</CODE>'' that creates and
returns a new Rectangle instead of modifying the old one.
returns a new Rectangle instead of modifying the old one.
</EM></FONT></FONT></DIV><H2 CLASS="section"><A NAME="toc171"></A><A NAME="htoc188"><FONT COLOR=black><FONT SIZE=3>15.7</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;Debugging</FONT></FONT></H2><P><FONT COLOR=black><FONT SIZE=3>
''</DIV>=== 15.7&#XA0;&#XA0;Debugging ===
</FONT></FONT><A NAME="hasattr"></A></P><P><A NAME="@default1408"></A></P><P><FONT COLOR=black><FONT SIZE=3>When you start working with objects, you are likely to encounter
 
 
 
 
When you start working with objects, you are likely to encounter
some new exceptions. If you try to access an attribute
some new exceptions. If you try to access an attribute
that doesn&#X2019;t exist, you get an </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>AttributeError</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>:</FONT></FONT></P><P><A NAME="@default1409"></A><FONT COLOR=black><FONT SIZE=3>
that doesn&#X2019;t exist, you get an <TT>AttributeError</TT>:
</FONT></FONT><A NAME="@default1410"></A></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>&gt;&gt;&gt; p = Point()
 
 
 
<PRE CLASS="verbatim">&gt;&gt;&gt; p = Point()
&gt;&gt;&gt; print p.z
&gt;&gt;&gt; print p.z
AttributeError: Point instance has no attribute 'z'
AttributeError: Point instance has no attribute 'z'
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>If you are not sure what type an object is, you can ask:</FONT></FONT></P><P><A NAME="@default1411"></A><FONT COLOR=black><FONT SIZE=3>
</PRE>
</FONT></FONT><A NAME="@default1412"></A></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>&gt;&gt;&gt; type(p)
If you are not sure what type an object is, you can ask:
 
 
 
<PRE CLASS="verbatim">&gt;&gt;&gt; type(p)
&lt;type '__main__.Point'&gt;
&lt;type '__main__.Point'&gt;
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>If you are not sure whether an object has a particular attribute,
</PRE>
you can use the built-in function </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>hasattr</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>:</FONT></FONT></P><P><A NAME="@default1413"></A><FONT COLOR=black><FONT SIZE=3>
If you are not sure whether an object has a particular attribute,
</FONT></FONT><A NAME="@default1414"></A></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>&gt;&gt;&gt; hasattr(p, 'x')
you can use the built-in function <TT>hasattr</TT>:
 
 
 
<PRE CLASS="verbatim">&gt;&gt;&gt; hasattr(p, 'x')
True
True
&gt;&gt;&gt; hasattr(p, 'z')
&gt;&gt;&gt; hasattr(p, 'z')
False
False
</FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>The first argument can be any object; the second argument is a </FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>string</EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3> that contains the name of the attribute.</FONT></FONT></P><H2 CLASS="section"><A NAME="toc172"></A><A NAME="htoc189"><FONT COLOR=black><FONT SIZE=3>15.8</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>class:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> A user-defined type. A class definition creates a new
</PRE>
The first argument can be any object; the second argument is a ''string'' that contains the name of the attribute.
=== 15.8&#XA0;&#XA0;Glossary ===
 
<DL CLASS="description"><DT CLASS="dt-description">'''class:'''</DT><DD CLASS="dd-description"> A user-defined type. A class definition creates a new
class object.
class object.
</FONT></FONT><A NAME="@default1415"></A></DD><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>class object:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> An object that contains information about a
</DD><DT CLASS="dt-description">'''class object:'''</DT><DD CLASS="dd-description"> An object that contains information about a
user-defined type. The class object can be used to create instances
user-defined type. The class object can be used to create instances
of the type.
of the type.
</FONT></FONT><A NAME="@default1416"></A></DD><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>instance:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> An object that belongs to a class.
</DD><DT CLASS="dt-description">'''instance:'''</DT><DD CLASS="dd-description"> An object that belongs to a class.
</FONT></FONT><A NAME="@default1417"></A></DD><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>attribute:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> One of the named values associated with an object.
</DD><DT CLASS="dt-description">'''attribute:'''</DT><DD CLASS="dd-description"> One of the named values associated with an object.
</FONT></FONT><A NAME="@default1418"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1419"></A></DD><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>embedded (object):</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> An object that is stored as an attribute
</DD><DT CLASS="dt-description">'''embedded (object):'''</DT><DD CLASS="dd-description"> An object that is stored as an attribute
of another object.
of another object.
</FONT></FONT><A NAME="@default1420"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1421"></A></DD><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>shallow copy:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> To copy the contents of an object, including
</DD><DT CLASS="dt-description">'''shallow copy:'''</DT><DD CLASS="dd-description"> To copy the contents of an object, including
any references to embedded objects;
any references to embedded objects;
implemented by the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>copy</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> function in the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>copy</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> module.
implemented by the <TT>copy</TT> function in the <TT>copy</TT> module.
</FONT></FONT><A NAME="@default1422"></A></DD><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>deep copy:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> To copy the contents of an object as well as any
</DD><DT CLASS="dt-description">'''deep copy:'''</DT><DD CLASS="dd-description"> To copy the contents of an object as well as any
embedded objects, and any objects embedded in them, and so on;
embedded objects, and any objects embedded in them, and so on;
implemented by the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>deepcopy</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> function in the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>copy</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> module.
implemented by the <TT>deepcopy</TT> function in the <TT>copy</TT> module.
</FONT></FONT><A NAME="@default1423"></A></DD><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>object diagram:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> A diagram that shows objects, their
</DD><DT CLASS="dt-description">'''object diagram:'''</DT><DD CLASS="dd-description"> A diagram that shows objects, their
attributes, and the values of the attributes.
attributes, and the values of the attributes.
</FONT></FONT><A NAME="@default1424"></A><FONT COLOR=black><FONT SIZE=3>
 
</FONT></FONT><A NAME="@default1425"></A></DD></DL><H2 CLASS="section"><A NAME="toc173"></A><A NAME="htoc190"><FONT COLOR=black><FONT SIZE=3>15.9</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;4</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>&#XA0;&#XA0;<EM>
</DD></DL>=== 15.9&#XA0;&#XA0;Exercises ===
</EM></FONT></FONT><A NAME="canvas"></A><P><A NAME="@default1426"></A><FONT COLOR=black><FONT SIZE=3><EM>
 
</EM></FONT></FONT><A NAME="@default1427"></A><FONT COLOR=black><FONT SIZE=3><EM>
<DIV CLASS="theorem">'''Exercise&#XA0;4'''&#XA0;&#XA0;''
</EM></FONT></FONT><A NAME="@default1428"></A></P><P><FONT COLOR=black><FONT SIZE=3><EM><TT>World.py</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>, which is part of Swampy (see 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>),
''
''
''''
''
 
''<TT>World.py</TT>'''', which is part of Swampy (see Chapter&#XA0;''''4''''),
contains a class definition for a user-defined type called  
contains a class definition for a user-defined type called  
</EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>World</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>. If you run this code:</EM></FONT></FONT></P><PRE CLASS="verbatim"><EM><FONT COLOR=blue><FONT SIZE=4>from World import *
''''<TT>World</TT>''''. If you run this code:''
<PRE CLASS="verbatim">''from World import *
world = World()
world = World()
wait_for_user()
wait_for_user()
</FONT></FONT></EM></PRE><P><EM><FONT COLOR=black><FONT SIZE=3>A window should appear with a title bar and an empty square.
''</PRE>
''A window should appear with a title bar and an empty square.
In this exercise we will use this window to draw Points,
In this exercise we will use this window to draw Points,
Rectangles and other shapes.  
Rectangles and other shapes.  
Add the following lines before
Add the following lines before
</FONT></FONT></EM><CODE><EM><FONT COLOR=black><FONT SIZE=3>wait_for_user</FONT></FONT></EM></CODE><EM><FONT COLOR=black><FONT SIZE=3> and run the program again</FONT></FONT></EM></P><P><A NAME="@default1429"></A><EM><FONT COLOR=black><FONT SIZE=3>
''<CODE>''wait_for_user''</CODE>'' and run the program again''
</FONT></FONT></EM><A NAME="@default1430"></A></P><PRE CLASS="verbatim"><EM><FONT COLOR=blue><FONT SIZE=4>canvas = world.ca(width=500, height=500, background='white')
 
''
''
<PRE CLASS="verbatim">''canvas = world.ca(width=500, height=500, background='white')
bbox = [[-150,-100], [150, 100]]
bbox = [[-150,-100], [150, 100]]
canvas.rectangle(bbox, outline='black', width=2, fill='green4')
canvas.rectangle(bbox, outline='black', width=2, fill='green4')
</FONT></FONT></EM></PRE><P><EM><FONT COLOR=black><FONT SIZE=3>You should see a green rectangle with a black outline.
''</PRE>
''You should see a green rectangle with a black outline.
The first line creates a Canvas, which appears in the window
The first line creates a Canvas, which appears in the window
as a white square. The Canvas object provides methods like
as a white square. The Canvas object provides methods like
</FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><TT>rectangle</TT></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3> for drawing various shapes.</FONT></FONT></EM></P><P><A NAME="@default1431"></A></P><P><EM><FONT COLOR=black><FONT SIZE=3><TT>bbox</TT></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3> is a list of lists that represents the &#X201C;bounding box&#X201D;
''''<TT>rectangle</TT>'''' for drawing various shapes.''
 
''<TT>bbox</TT>'''' is a list of lists that represents the &#X201C;bounding box&#X201D;
of the rectangle. The first pair of coordinates is the lower-left
of the rectangle. The first pair of coordinates is the lower-left
corner of the rectangle; the second pair is the upper-right corner.</FONT></FONT></EM></P><P><EM><FONT COLOR=black><FONT SIZE=3>You can draw a circle like this:</FONT></FONT></EM></P><PRE CLASS="verbatim"><EM><FONT COLOR=blue><FONT SIZE=4>canvas.circle([-25,0], 70, outline=None, fill='red')
corner of the rectangle; the second pair is the upper-right corner.''
</FONT></FONT></EM></PRE><P><A NAME="@default1432"></A></P><P><EM><FONT COLOR=black><FONT SIZE=3>The first parameter is the coordinate pair for the center of the
 
circle; the second parameter is the radius.</FONT></FONT></EM></P><P><EM><FONT COLOR=black><FONT SIZE=3>If you add this line to the program,  
''You can draw a circle like this:''
<PRE CLASS="verbatim">''canvas.circle([-25,0], 70, outline=None, fill='red')
''</PRE>
 
''The first parameter is the coordinate pair for the center of the
circle; the second parameter is the radius.''
 
''If you add this line to the program,  
the result should resemble the national flag of Bangladesh
the result should resemble the national flag of Bangladesh
(see </FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><TT>wikipedia.org/wiki/Gallery_of_sovereign-state_flags</TT></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3>).</FONT></FONT></EM></P><OL CLASS="enumerate" type=1><LI CLASS="li-enumerate"><EM><FONT COLOR=black><FONT SIZE=3>Write a function called </FONT></FONT></EM><CODE><EM><FONT COLOR=black><FONT SIZE=3>draw_rectangle</FONT></FONT></EM></CODE><EM><FONT COLOR=black><FONT SIZE=3> that takes a
(see ''''<TT>wikipedia.org/wiki/Gallery_of_sovereign-state_flags</TT>'''').''
 
*''Write a function called ''<CODE>''draw_rectangle''</CODE>'' that takes a
Canvas and a Rectangle as arguments and draws a
Canvas and a Rectangle as arguments and draws a
representation of the Rectangle on the Canvas.</FONT></FONT></EM></LI><LI CLASS="li-enumerate"><EM><FONT COLOR=black><FONT SIZE=3>Add an attribute named </FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><TT>color</TT></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3> to your Rectangle objects and
representation of the Rectangle on the Canvas.''
modify </FONT></FONT></EM><CODE><EM><FONT COLOR=black><FONT SIZE=3>draw_rectangle</FONT></FONT></EM></CODE><EM><FONT COLOR=black><FONT SIZE=3> so that it uses the color attribute as
 
the fill color.</FONT></FONT></EM></LI><LI CLASS="li-enumerate"><EM><FONT COLOR=black><FONT SIZE=3>Write a function called </FONT></FONT></EM><CODE><EM><FONT COLOR=black><FONT SIZE=3>draw_point</FONT></FONT></EM></CODE><EM><FONT COLOR=black><FONT SIZE=3> that takes a
*''Add an attribute named ''''<TT>color</TT>'''' to your Rectangle objects and
modify ''<CODE>''draw_rectangle''</CODE>'' so that it uses the color attribute as
the fill color.''
 
*''Write a function called ''<CODE>''draw_point''</CODE>'' that takes a
Canvas and a Point as arguments and draws a
Canvas and a Point as arguments and draws a
representation of the Point on the Canvas.</FONT></FONT></EM></LI><LI CLASS="li-enumerate"><EM><FONT COLOR=black><FONT SIZE=3>Define a new class called Circle with appropriate attributes and
representation of the Point on the Canvas.''
 
*''Define a new class called Circle with appropriate attributes and
instantiate a few Circle objects. Write a function called
instantiate a few Circle objects. Write a function called
</FONT></FONT></EM><CODE><EM><FONT COLOR=black><FONT SIZE=3>draw_circle</FONT></FONT></EM></CODE><EM><FONT COLOR=black><FONT SIZE=3> that draws circles on the canvas.</FONT></FONT></EM><P><A NAME="@default1433"></A></P></LI><LI CLASS="li-enumerate"><EM><FONT COLOR=black><FONT SIZE=3>Write a program that draws the national flag of of the Czech Republic.
''<CODE>''draw_circle''</CODE>'' that draws circles on the canvas.''
Hint: you can draw a polygon like this:</FONT></FONT></EM><PRE CLASS="verbatim"><EM><FONT COLOR=blue><FONT SIZE=4>points = [[-150,-100], [150, 100], [150, -100]]
 
*''Write a program that draws the national flag of of the Czech Republic.
Hint: you can draw a polygon like this:''<PRE CLASS="verbatim">''points = [[-150,-100], [150, 100], [150, -100]]
canvas.polygon(points, fill='blue')
canvas.polygon(points, fill='blue')
</FONT></FONT></EM></PRE></LI></OL><P><A NAME="@default1434"></A><EM><FONT COLOR=black><FONT SIZE=3>
''</PRE>
</FONT></FONT></EM><A NAME="@default1435"></A></P><P><EM><FONT COLOR=black><FONT SIZE=3>I have written a small program that lists the available colors;
 
you can download it from </FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><TT>thinkpython.com/code/color_list.py</TT></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3>.</FONT></FONT></EM></P></DIV><HR>
''
<A HREF="book015.html"><IMG SRC="previous_motif.gif" ALT="Previous"></A>
''
<A HREF="index.html"><IMG SRC="contents_motif.gif" ALT="Up"></A>
 
<A HREF="book017.html"><IMG SRC="next_motif.gif" ALT="Next"></A>
''I have written a small program that lists the available colors;
</BODY>
you can download it from ''''<TT>thinkpython.com/code/color_list.py</TT>''''.''
</HTML>
</DIV><HR>
<IMG SRC="previous_motif.gif" ALT="Previous">
<IMG SRC="contents_motif.gif" ALT="Up">
<IMG SRC="next_motif.gif" ALT="Next">

Revision as of 23:09, 15 September 2008

Chapter 15  Classes and objects

15.1  User-defined types

We have used many of Python’s built-in types; now we are going to define a new type. As an example, we will create a type called Point that represents a point in two-dimensional space.

In mathematical notation, points are often written in parentheses with a comma separating the coordinates. For example, (0, 0) represents the origin, and (x, y) represents the point x units to the right and y units up from the origin.

There are several ways we might represent points in Python:

  • We could store the coordinates separately in two

variables, x and y.

  • We could store the coordinates as elements in a list

or tuple.

  • We could create a new type to represent points as

objects.

Creating a new type is (a little) more complicated than the other options, but it has advantages that will be apparent soon.

A user-defined type is also called a class. A class definition looks like this:



class Point(object):
    """represents a point in 2-D space"""

This header indicates that the new class is a Point, which is a kind of object, which is a built-in type.



The body is a docstring that explains what the class is for. You can define variables and functions inside a class definition, but we will get back to that later.

Defining a class named Point creates a class object.

>>> print Point
<class '__main__.Point'>

Because Point is defined at the top level, its “full name” is __main__.Point.



The class object is like a factory for creating objects. To create a Point, you call Point as if it were a function.

>>> blank = Point()
>>> print blank
<__main__.Point instance at 0xb7e9d3ac>

The return value is a reference to a Point object, which we assign to blank. Creating a new object is called instantiation, and the object is an instance of the class.



When you print an instance, Python tells you what class it belongs to and where it is stored in memory (the prefix 0x means that the following number is in hexadecimal).

15.2  Attributes

You can assign values to an instance using dot notation:

>>> blank.x = 3.0
>>> blank.y = 4.0

This syntax is similar to the syntax for selecting a variable from a module, such as math.pi or string.whitespace. In this case, though, we are assigning values to named elements of an object. These elements are called attributes.

As a noun, “AT-trib-ute” is pronounced with emphasis on the first syllable, as opposed to “a-TRIB-ute,” which is a verb.

The following diagram shows the result of these assignments. A state diagram that shows an object and its attributes is called an object diagram:



<IMG SRC="book022.png">

The variable blank refers to a Point object, which contains two attributes. Each attribute refers to a floating-point number.

You can read the value of an attribute using the same syntax:

>>> print blank.y
4.0
>>> x = blank.x
>>> print x
3.0

The expression blank.x means, “Go to the object blank refers to and get the value of x.” In this case, we assign that value to a variable named x. There is no conflict between the variable x and the attribute x.

You can use dot notation as part of any expression. For example:

>>> print '(%g, %g)' % (blank.x, blank.y)
(3.0, 4.0)
>>> distance = math.sqrt(blank.x**2 + blank.y**2)
>>> print distance
5.0

You can pass an instance as an argument in the usual way. For example:

def print_point(p):
    print '(%g, %g)' % (p.x, p.y)

print_point takes a point as an argument and displays it in mathematical notation. To invoke it, you can pass blank as an argument:

>>> print_point(blank)
(3.0, 4.0)

Inside the function, p is an alias for blank, so if the function modifies p, blank changes.

Exercise 1  

Write a function called 'distance' that it takes two Points as arguments and returns the distance between them.

=== 15.3  Rectangles ===

Sometimes it is obvious what the attributes of an object should be, but other times you have to make decisions. For example, imagine you are designing a class to represent rectangles. What attributes would you use to specify the location and size of a rectangle? You can ignore angle; to keep things simple, assume that the rectangle is either vertical or horizontal.

There are at least two possibilities:

  • You could specify one corner of the rectangle

(or the center), the width, and the height.

  • You could specify two opposing corners.

At this point it is hard to say whether either is better than the other, so we’ll implement the first one, just as an example.



Here is the class definition:

class Rectangle(object):
    """represent a rectangle. 
       attributes: width, height, corner.
    """

The docstring lists the attributes: width and height are numbers; corner is a Point object that specifies the lower-left corner.

To represent a rectangle, you have to instantiate a Rectangle object and assign values to the attributes:

box = Rectangle()
box.width = 100.0
box.height = 200.0
box.corner = Point()
box.corner.x = 0.0
box.corner.y = 0.0

The expression box.corner.x means, “Go to the object box refers to and select the attribute named corner; then go to that object and select the attribute named x.”

The figure shows the state of this object:



<IMG SRC="book023.png">

An object that is an attribute of another object is embedded.


15.4  Instances as return values

Functions can return instances. For example, find_center takes a Rectangle as an argument and returns a Point that contains the coordinates of the center of the Rectangle:

def find_center(box):
    p = Point()
    p.x = box.corner.x + box.width/2.0
    p.y = box.corner.y + box.height/2.0
    return p

Here is an example that passes box as an argument and assigns the resulting Point to center:

>>> center = find_center(box)
>>> print_point(center)
(50.0, 100.0)

=== 15.5  Objects are mutable ===



You can change the state of an object by making an assignment to one of its attributes. For example, to change the size of a rectangle without changing its position, you can modify the values of width and height:

box.width = box.width + 50
box.height = box.width + 100

You can also write functions that modify objects. For example, grow_rectangle takes a Rectangle object and two numbers, dwidth and dheight, and adds the numbers to the width and height of the rectangle:

def grow_rectangle(rect, dwidth, dheight) :
    rect.width += dwidth
    rect.height += dheight

Here is an example that demonstrates the effect:

>>> print box.width
100.0
>>> print box.height
200.0
>>> grow_rectangle(box, 50, 100)
>>> print box.width
150.0
>>> print box.height
300.0

Inside the function, rect is an alias for box, so if the function modifies rect, box changes.

Exercise 2  

Write a function named move_rectangle that takes a Rectangle and two numbers named 'dx' and 'dy'. It should change the location of the rectangle by adding 'dx' to the 'x' coordinate of 'corner' and adding 'dy' to the 'y' coordinate of 'corner'.

=== 15.6  Copying ===

Aliasing can make a program difficult to read because changes in one place might have unexpected effects in another place. It is hard to keep track of all the variables that might refer to a given object.




Copying an object is often an alternative to aliasing. The copy module contains a function called copy that can duplicate any object:

>>> p1 = Point()
>>> p1.x = 3.0
>>> p1.y = 4.0

>>> import copy
>>> p2 = copy.copy(p1)

p1 and p2 contain the same data, but they are not the same Point.

>>> print_point(p1)
(3.0, 4.0)
>>> print_point(p2)
(3.0, 4.0)
>>> p1 is p2
False
>>> p1 == p2
False

The is operator indicates that p1 and p2 are not the same object, which is what we expected. But you might have expected == to yield True because these points contain the same data. In that case, you will be disappointed to learn that for instances, the default behavior of the == operator is the same as the is operator; it checks object identity, not object equivalence. This behavior can be changed—we’ll see how later.



If you use copy.copy to duplicate a Rectangle, you will find that it copies the Rectangle object but not the embedded Point.

>>> box2 = copy.copy(box)
>>> box2 is box
False
>>> box2.corner is box.corner
True

Here is what the object diagram looks like:






<IMG SRC="book024.png">



This operation is called a shallow copy because it copies the object and any references it contains, but not the embedded objects.



For most applications, this is not what you want. In this example, invoking grow_rectangle on one of the Rectangles would not affect the other, but invoking move_rectangle on either would affect both! This behavior is confusing and error-prone.



Fortunately, the copy module contains a method named deepcopy that copies not only the object but also the objects it refers to, and the objects they refer to, and so on. You will not be surprised to learn that this operation is called a deep copy.


>>> box3 = copy.deepcopy(box)
>>> box3 is box
False
>>> box3.corner is box.corner
False

box3 and box are completely separate objects.

Exercise 3  

Write a version of move_rectangle that creates and returns a new Rectangle instead of modifying the old one.

=== 15.7  Debugging ===



When you start working with objects, you are likely to encounter some new exceptions. If you try to access an attribute that doesn’t exist, you get an AttributeError:


>>> p = Point()
>>> print p.z
AttributeError: Point instance has no attribute 'z'

If you are not sure what type an object is, you can ask:


>>> type(p)
<type '__main__.Point'>

If you are not sure whether an object has a particular attribute, you can use the built-in function hasattr:


>>> hasattr(p, 'x')
True
>>> hasattr(p, 'z')
False

The first argument can be any object; the second argument is a string that contains the name of the attribute.

15.8  Glossary

class:
A user-defined type. A class definition creates a new class object.
class object:
An object that contains information about a user-defined type. The class object can be used to create instances of the type.
instance:
An object that belongs to a class.
attribute:
One of the named values associated with an object.
embedded (object):
An object that is stored as an attribute of another object.
shallow copy:
To copy the contents of an object, including any references to embedded objects; implemented by the copy function in the copy module.
deep copy:
To copy the contents of an object as well as any embedded objects, and any objects embedded in them, and so on; implemented by the deepcopy function in the copy module.
object diagram:
A diagram that shows objects, their attributes, and the values of the attributes.

=== 15.9  Exercises ===

Exercise 4  

'

World.py'', which is part of Swampy (see Chapter '4'), contains a class definition for a user-defined type called 'World'. If you run this code:

''from World import *
world = World()
wait_for_user()
''

A window should appear with a title bar and an empty square. In this exercise we will use this window to draw Points, Rectangles and other shapes. Add the following lines before wait_for_user and run the program again

''canvas = world.ca(width=500, height=500, background='white')
bbox = [[-150,-100], [150, 100]]
canvas.rectangle(bbox, outline='black', width=2, fill='green4')
''

You should see a green rectangle with a black outline. The first line creates a Canvas, which appears in the window as a white square. The Canvas object provides methods like 'rectangle' for drawing various shapes.

bbox'' is a list of lists that represents the “bounding box” of the rectangle. The first pair of coordinates is the lower-left corner of the rectangle; the second pair is the upper-right corner.

You can draw a circle like this:

''canvas.circle([-25,0], 70, outline=None, fill='red')
''

The first parameter is the coordinate pair for the center of the circle; the second parameter is the radius.

If you add this line to the program, the result should resemble the national flag of Bangladesh (see 'wikipedia.org/wiki/Gallery_of_sovereign-state_flags').

  • Write a function called draw_rectangle that takes a

Canvas and a Rectangle as arguments and draws a representation of the Rectangle on the Canvas.

  • Add an attribute named 'color' to your Rectangle objects and

modify draw_rectangle so that it uses the color attribute as the fill color.

  • Write a function called draw_point that takes a

Canvas and a Point as arguments and draws a representation of the Point on the Canvas.

  • Define a new class called Circle with appropriate attributes and

instantiate a few Circle objects. Write a function called draw_circle that draws circles on the canvas.

  • Write a program that draws the national flag of of the Czech Republic.
Hint: you can draw a polygon like this:
''points = [[-150,-100], [150, 100], [150, -100]]
canvas.polygon(points, fill='blue')
''

I have written a small program that lists the available colors; you can download it from 'thinkpython.com/code/color_list.py'.


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