|
|
| 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 17  Classes and methods == |
| <META name="GENERATOR" content="hevea 1.10">
| | |
| <LINK rel="stylesheet" type="text/css" href="book.css">
| | === 17.1  Object-oriented features === |
| <TITLE>Classes and methods</TITLE>
| | |
| </HEAD>
| | Python is an '''object-oriented programming language''', which means |
| <BODY >
| |
| <A HREF="book017.html"><IMG SRC="previous_motif.gif" ALT="Previous"></A>
| |
| <A HREF="index.html"><IMG SRC="contents_motif.gif" ALT="Up"></A>
| |
| <A HREF="book019.html"><IMG SRC="next_motif.gif" ALT="Next"></A>
| |
| <HR>
| |
| <H1 CLASS="chapter"><A NAME="htoc199"><FONT COLOR=black><FONT SIZE=3>Chapter 17</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>  Classes and methods</FONT></FONT></H1><H2 CLASS="section"><A NAME="toc181"></A><A NAME="htoc200"><FONT COLOR=black><FONT SIZE=3>17.1</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>  Object-oriented features</FONT></FONT></H2><P><A NAME="@default1485"></A></P><P><FONT COLOR=black><FONT SIZE=3>Python is an </FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>object-oriented programming language</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, which means
| |
| that it provides features that support object-oriented | | that it provides features that support object-oriented |
| programming.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>It is not easy to define object-oriented programming, but we have | | programming. |
| already seen some of its characteristics:</FONT></FONT></P><UL CLASS="itemize"><LI CLASS="li-itemize"><FONT COLOR=black><FONT SIZE=3>Programs are made up of object definitions and function | | |
| | It is not easy to define object-oriented programming, but we have |
| | already seen some of its characteristics: |
| | |
| | *Programs are made up of object definitions and function |
| definitions, and most of the computation is expressed in terms | | definitions, and most of the computation is expressed in terms |
| of operations on objects.</FONT></FONT></LI><LI CLASS="li-itemize"><FONT COLOR=black><FONT SIZE=3>Each object definition corresponds to some object or concept | | of operations on objects. |
| | |
| | *Each object definition corresponds to some object or concept |
| in the real world, and the functions that operate on that object | | in the real world, and the functions that operate on that object |
| correspond to the ways real-world objects interact.</FONT></FONT></LI></UL><P><FONT COLOR=black><FONT SIZE=3>For example, the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Time</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> class defined in Chapter </FONT></FONT><A HREF="book017.html#time"><FONT COLOR=black><FONT SIZE=3>16</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3> | | correspond to the ways real-world objects interact. |
| | |
| | For example, the <TT>Time</TT> class defined in Chapter 16 |
| corresponds to the way people record the time of day, and the | | corresponds to the way people record the time of day, and the |
| functions we defined correspond to the kinds of things people do with | | functions we defined correspond to the kinds of things people do with |
| times. Similarly, the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Point</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> and </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Rectangle</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> classes | | times. Similarly, the <TT>Point</TT> and <TT>Rectangle</TT> classes |
| correspond to the mathematical concepts of a point and a rectangle.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>So far, we have not taken advantage of the features Python provides to | | correspond to the mathematical concepts of a point and a rectangle. |
| | |
| | So far, we have not taken advantage of the features Python provides to |
| support object-oriented programming. These | | support object-oriented programming. These |
| features are not strictly necessary; most of them provide | | features are not strictly necessary; most of them provide |
| alternative syntax for things we have already done. But in many cases, | | alternative syntax for things we have already done. But in many cases, |
| the alternative is more concise and more accurately conveys the | | the alternative is more concise and more accurately conveys the |
| structure of the program.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>For example, in the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Time</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> program, there is no obvious | | structure of the program. |
| | |
| | For example, in the <TT>Time</TT> program, there is no obvious |
| connection between the class definition and the function definitions | | connection between the class definition and the function definitions |
| that follow. With some examination, it is apparent that every function | | that follow. With some examination, it is apparent that every function |
| takes at least one </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Time</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> object as an argument.</FONT></FONT></P><P><A NAME="@default1486"></A><FONT COLOR=black><FONT SIZE=3> | | takes at least one <TT>Time</TT> object as an argument. |
| </FONT></FONT><A NAME="@default1487"></A></P><P><FONT COLOR=black><FONT SIZE=3>This observation is the motivation for </FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>methods</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>; a method is
| | |
| | |
| | |
| | |
| | This observation is the motivation for '''methods'''; a method is |
| a function that is associated with a particular class. | | a function that is associated with a particular class. |
| We have seen methods for strings, lists, dictionaries and tuples. | | We have seen methods for strings, lists, dictionaries and tuples. |
| In this chapter, we will define methods for user-defined types.</FONT></FONT></P><P><A NAME="@default1488"></A><FONT COLOR=black><FONT SIZE=3> | | In this chapter, we will define methods for user-defined types. |
| </FONT></FONT><A NAME="@default1489"></A></P><P><FONT COLOR=black><FONT SIZE=3>Methods are semantically the same as functions, but there are
| | |
| two syntactic differences:</FONT></FONT></P><UL CLASS="itemize"><LI CLASS="li-itemize"><FONT COLOR=black><FONT SIZE=3>Methods are defined inside a class definition in order | | |
| to make the relationship between the class and the method explicit.</FONT></FONT></LI><LI CLASS="li-itemize"><FONT COLOR=black><FONT SIZE=3>The syntax for invoking a method is different from the | | |
| syntax for calling a function.</FONT></FONT></LI></UL><P><FONT COLOR=black><FONT SIZE=3>In the next few sections, we will take the functions from the previous | | |
| | Methods are semantically the same as functions, but there are |
| | two syntactic differences: |
| | |
| | *Methods are defined inside a class definition in order |
| | to make the relationship between the class and the method explicit. |
| | |
| | *The syntax for invoking a method is different from the |
| | syntax for calling a function. |
| | |
| | In the next few sections, we will take the functions from the previous |
| two chapters and transform them into methods. This transformation is | | two chapters and transform them into methods. This transformation is |
| purely mechanical; you can do it simply by following a sequence of | | purely mechanical; you can do it simply by following a sequence of |
| steps. If you are comfortable converting from one form to another, | | steps. If you are comfortable converting from one form to another, |
| you will be able to choose the best form for whatever you are doing.</FONT></FONT></P><H2 CLASS="section"><A NAME="toc182"></A><A NAME="htoc201"><FONT COLOR=black><FONT SIZE=3>17.2</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>  Printing objects</FONT></FONT></H2><P><FONT COLOR=black><FONT SIZE=3> | | you will be able to choose the best form for whatever you are doing. |
| </FONT></FONT><A NAME="print_time"></A></P><P><A NAME="@default1490"></A></P><P><FONT COLOR=black><FONT SIZE=3>In Chapter </FONT></FONT><A HREF="book017.html#time"><FONT COLOR=black><FONT SIZE=3>16</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>, we defined a class named
| | === 17.2  Printing objects === |
| </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Time</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> and in Exercise </FONT></FONT><A HREF="book017.html#printtime"><FONT COLOR=black><FONT SIZE=3>16.1</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>, you
| | |
| wrote a function named </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>print_time</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>class Time(object): | | |
| | |
| | |
| | In Chapter 16, we defined a class named |
| | <TT>Time</TT> and in Exercise 16.1, you |
| | wrote a function named <CODE>print_time</CODE>: |
| | <PRE CLASS="verbatim">class Time(object): |
| """represents the time of day. | | """represents the time of day. |
| attributes: hour, minute, second""" | | attributes: hour, minute, second""" |
| Line 54: |
Line 77: |
| def print_time(time): | | def print_time(time): |
| print '%.2d:%.2d:%.2d' % (time.hour, time.minute, time.second) | | print '%.2d:%.2d:%.2d' % (time.hour, time.minute, time.second) |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>To call this function, you have to pass a </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Time</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> object as an
| | </PRE> |
| argument:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>>>> start = Time() | | To call this function, you have to pass a <TT>Time</TT> object as an |
| | argument: |
| | <PRE CLASS="verbatim">>>> start = Time() |
| >>> start.hour = 9 | | >>> start.hour = 9 |
| >>> start.minute = 45 | | >>> start.minute = 45 |
| Line 61: |
Line 86: |
| >>> print_time(start) | | >>> print_time(start) |
| 09:45:00 | | 09:45:00 |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>To make </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>print_time</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> a method, all we have to do is
| | </PRE> |
| | To make <CODE>print_time</CODE> a method, all we have to do is |
| move the function definition inside the class definition. Notice | | move the function definition inside the class definition. Notice |
| the change in indentation.</FONT></FONT></P><P><A NAME="@default1491"></A></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>class Time(object): | | the change in indentation. |
| | |
| | <PRE CLASS="verbatim">class Time(object): |
| def print_time(time): | | def print_time(time): |
| print '%.2d:%.2d:%.2d' % (time.hour, time.minute, time.second) | | print '%.2d:%.2d:%.2d' % (time.hour, time.minute, time.second) |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>Now there are two ways to call </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>print_time</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>. The first
| | </PRE> |
| (and less common) way is to use function syntax:</FONT></FONT></P><P><A NAME="@default1492"></A><FONT COLOR=black><FONT SIZE=3> | | Now there are two ways to call <CODE>print_time</CODE>. The first |
| </FONT></FONT><A NAME="@default1493"></A></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>>>> Time.print_time(start)
| | (and less common) way is to use function syntax: |
| | |
| | |
| | |
| | <PRE CLASS="verbatim">>>> Time.print_time(start) |
| 09:45:00 | | 09:45:00 |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>In this use of dot notation, </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Time</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> is the name of the class,
| | </PRE> |
| and </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>print_time</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> is the name of the method. </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>start</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> is | | In this use of dot notation, <TT>Time</TT> is the name of the class, |
| passed as a parameter.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>The second (and more concise) way is to use method syntax:</FONT></FONT></P><P><A NAME="@default1494"></A></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>>>> start.print_time() | | and <CODE>print_time</CODE> is the name of the method. <TT>start</TT> is |
| | passed as a parameter. |
| | |
| | The second (and more concise) way is to use method syntax: |
| | |
| | <PRE CLASS="verbatim">>>> start.print_time() |
| 09:45:00 | | 09:45:00 |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>In this use of dot notation, </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>print_time</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> is the name of the
| | </PRE> |
| method (again), and </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>start</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> is the object the method is | | In this use of dot notation, <CODE>print_time</CODE> is the name of the |
| invoked on, which is called the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>subject</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>. Just as the | | method (again), and <TT>start</TT> is the object the method is |
| | invoked on, which is called the '''subject'''. Just as the |
| subject of a sentence is what the sentence is about, the subject | | subject of a sentence is what the sentence is about, the subject |
| of a method invocation is what the method is about.</FONT></FONT></P><P><A NAME="@default1495"></A></P><P><FONT COLOR=black><FONT SIZE=3>Inside the method, the subject is assigned to the first | | of a method invocation is what the method is about. |
| parameter, so in this case </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>start</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> is assigned | | |
| to </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>time</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.</FONT></FONT></P><P><A NAME="@default1496"></A><FONT COLOR=black><FONT SIZE=3> | | Inside the method, the subject is assigned to the first |
| </FONT></FONT><A NAME="@default1497"></A></P><P><FONT COLOR=black><FONT SIZE=3>By convention, the first parameter of a method is
| | parameter, so in this case <TT>start</TT> is assigned |
| called </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>self</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, so it would be more common to write | | to <TT>time</TT>. |
| </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>print_time</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> like this:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>class Time(object):
| | |
| | |
| | |
| | |
| | By convention, the first parameter of a method is |
| | called <TT>self</TT>, so it would be more common to write |
| | <CODE>print_time</CODE> like this: |
| | <PRE CLASS="verbatim">class Time(object): |
| def print_time(self): | | def print_time(self): |
| print '%.2d:%.2d:%.2d' % (self.hour, self.minute, self.second) | | print '%.2d:%.2d:%.2d' % (self.hour, self.minute, self.second) |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>The reason for this convention is an implicit metaphor:</FONT></FONT></P><P><A NAME="@default1498"></A></P><UL CLASS="itemize"><LI CLASS="li-itemize"><FONT COLOR=black><FONT SIZE=3>The syntax for a function call, </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>print_time(start)</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>,
| | </PRE> |
| | The reason for this convention is an implicit metaphor: |
| | |
| | *The syntax for a function call, <CODE>print_time(start)</CODE>, |
| suggests that the function is the active agent. It says something | | suggests that the function is the active agent. It says something |
| like, “Hey </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>print_time</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>! Here’s an object for you to print.”</FONT></FONT></LI><LI CLASS="li-itemize"><FONT COLOR=black><FONT SIZE=3>In object-oriented programming, the objects are the active | | like, “Hey <CODE>print_time</CODE>! Here’s an object for you to print.” |
| agents. A method invocation like </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>start.print_time()</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> says | | |
| “Hey </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>start</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>! Please print yourself.”</FONT></FONT></LI></UL><P><FONT COLOR=black><FONT SIZE=3>This change in perspective might be more polite, but it is not obvious | | *In object-oriented programming, the objects are the active |
| | agents. A method invocation like <CODE>start.print_time()</CODE> says |
| | “Hey <TT>start</TT>! Please print yourself.” |
| | |
| | This change in perspective might be more polite, but it is not obvious |
| that it is useful. In the examples we have seen so far, it may not | | that it is useful. In the examples we have seen so far, it may not |
| be. But sometimes shifting responsibility from the functions onto the | | be. But sometimes shifting responsibility from the functions onto the |
| objects makes it possible to write more versatile functions, and makes | | objects makes it possible to write more versatile functions, and makes |
| it easier to maintain and reuse code.</FONT></FONT></P><DIV CLASS="theorem"><FONT COLOR=black><FONT SIZE=3><B>Exercise 1</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>  <EM> | | it easier to maintain and reuse code. |
| </EM></FONT></FONT><A NAME="convert"></A><FONT COLOR=black><FONT SIZE=3><EM>
| | <DIV CLASS="theorem">'''Exercise 1'''  '' |
| Rewrite </EM></FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3><EM>time_to_int</EM></FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3><EM> | | '''' |
| (from Section </EM></FONT></FONT><A HREF="book017.html#prototype"><FONT COLOR=black><FONT SIZE=3><EM>16.4</EM></FONT></FONT></A><FONT COLOR=black><FONT SIZE=3><EM>) as a method. It is probably not | | Rewrite ''<CODE>''time_to_int''</CODE>'' |
| appropriate to rewrite </EM></FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3><EM>int_to_time</EM></FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3><EM> as a method; it’s not | | (from Section ''''16.4'''') as a method. It is probably not |
| | appropriate to rewrite ''<CODE>''int_to_time''</CODE>'' as a method; it’s not |
| clear what object you would invoke it on! | | clear what object you would invoke it on! |
| </EM></FONT></FONT></DIV><H2 CLASS="section"><A NAME="toc183"></A><A NAME="htoc202"><FONT COLOR=black><FONT SIZE=3>17.3</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>  Another example</FONT></FONT></H2><P><A NAME="@default1499"></A></P><P><FONT COLOR=black><FONT SIZE=3>Here’s a version of </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>increment</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> (from Section </FONT></FONT><A HREF="book017.html#increment"><FONT COLOR=black><FONT SIZE=3>16.3</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>)
| | ''</DIV>=== 17.3  Another example === |
| rewritten as a method:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4># inside class Time: | | |
| | Here’s a version of <TT>increment</TT> (from Section 16.3) |
| | rewritten as a method: |
| | <PRE CLASS="verbatim"># inside class Time: |
|
| |
|
| def increment(self, seconds): | | def increment(self, seconds): |
| seconds += self.time_to_int() | | seconds += self.time_to_int() |
| return int_to_time(seconds) | | return int_to_time(seconds) |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>This version assumes that </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>time_to_int</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> is written
| | </PRE> |
| as a method, as in Exercise </FONT></FONT><A HREF="#convert"><FONT COLOR=black><FONT SIZE=3>17.1</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>. Also, note that | | This version assumes that <CODE>time_to_int</CODE> is written |
| it is a pure function, not a modifier.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>Here’s how you would invoke </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>increment</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>>>> start.print_time() | | as a method, as in Exercise 17.1. Also, note that |
| | it is a pure function, not a modifier. |
| | |
| | Here’s how you would invoke <TT>increment</TT>: |
| | <PRE CLASS="verbatim">>>> start.print_time() |
| 09:45:00 | | 09:45:00 |
| >>> end = start.increment(1337) | | >>> end = start.increment(1337) |
| >>> end.print_time() | | >>> end.print_time() |
| 10:07:17 | | 10:07:17 |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>The subject, </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>start</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, gets assigned to the first parameter,
| | </PRE> |
| </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>self</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>. The argument, </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>1337</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, gets assigned to the
| | The subject, <TT>start</TT>, gets assigned to the first parameter, |
| second parameter, </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>seconds</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>This mechanism can be confusing, especially if you make an error. | | <TT>self</TT>. The argument, <TT>1337</TT>, gets assigned to the |
| For example, if you invoke </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>increment</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> with two arguments, you | | second parameter, <TT>seconds</TT>. |
| get:</FONT></FONT></P><P><A NAME="@default1500"></A><FONT COLOR=black><FONT SIZE=3> | | |
| </FONT></FONT><A NAME="@default1501"></A></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>>>> end = start.increment(1337, 460)
| | This mechanism can be confusing, especially if you make an error. |
| | For example, if you invoke <TT>increment</TT> with two arguments, you |
| | get: |
| | |
| | |
| | |
| | <PRE CLASS="verbatim">>>> end = start.increment(1337, 460) |
| TypeError: increment() takes exactly 2 arguments (3 given) | | TypeError: increment() takes exactly 2 arguments (3 given) |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>The error message is initially confusing, because there are
| | </PRE> |
| | The error message is initially confusing, because there are |
| only two arguments in parentheses. But the subject is also | | only two arguments in parentheses. But the subject is also |
| considered an argument, so all together that’s three.</FONT></FONT></P><H2 CLASS="section"><A NAME="toc184"></A><A NAME="htoc203"><FONT COLOR=black><FONT SIZE=3>17.4</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>  A more complicated example</FONT></FONT></H2><P><CODE><FONT COLOR=black><FONT SIZE=3>is_after</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> (from Exercise </FONT></FONT><A HREF="book017.html#is_after"><FONT COLOR=black><FONT SIZE=3>16.2</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>) is slightly more complicated | | considered an argument, so all together that’s three. |
| | === 17.4  A more complicated example === |
| | |
| | <CODE>is_after</CODE> (from Exercise 16.2) is slightly more complicated |
| because it takes two Time objects as parameters. In this case it is | | because it takes two Time objects as parameters. In this case it is |
| conventional to name the first parameter </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>self</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> and the second | | conventional to name the first parameter <TT>self</TT> and the second |
| parameter </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>other</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>:</FONT></FONT></P><P><A NAME="@default1502"></A><FONT COLOR=black><FONT SIZE=3> | | parameter <TT>other</TT>: |
| </FONT></FONT><A NAME="@default1503"></A></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4># inside class Time:
| | |
| | |
| | |
| | <PRE CLASS="verbatim"># inside class Time: |
|
| |
|
| def is_after(self, other): | | def is_after(self, other): |
| return self.time_to_int() > other.time_to_int() | | return self.time_to_int() > other.time_to_int() |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>To use this method, you have to invoke it on one object and pass
| | </PRE> |
| the other as an argument:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>>>> end.is_after(start) | | To use this method, you have to invoke it on one object and pass |
| | the other as an argument: |
| | <PRE CLASS="verbatim">>>> end.is_after(start) |
| True | | True |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>One nice thing about this syntax is that it almost reads
| | </PRE> |
| like English: “end is after start?”</FONT></FONT></P><H2 CLASS="section"><A NAME="toc185"></A><A NAME="htoc204"><FONT COLOR=black><FONT SIZE=3>17.5</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>  The init method</FONT></FONT></H2><P><A NAME="@default1504"></A><FONT COLOR=black><FONT SIZE=3> | | One nice thing about this syntax is that it almost reads |
| </FONT></FONT><A NAME="@default1505"></A></P><P><FONT COLOR=black><FONT SIZE=3>The init method (short for “initialization”) is
| | like English: “end is after start?” |
| | === 17.5  The init method === |
| | |
| | |
| | |
| | |
| | The init method (short for “initialization”) is |
| a special method that gets invoked when an object is instantiated. | | a special method that gets invoked when an object is instantiated. |
| Its full name is </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>__init__</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> (two underscore characters, | | Its full name is <CODE>__init__</CODE> (two underscore characters, |
| followed by </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>init</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, and then two more underscores). An | | followed by <TT>init</TT>, and then two more underscores). An |
| init method for the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Time</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> class might look like this:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4># inside class Time: | | init method for the <TT>Time</TT> class might look like this: |
| | <PRE CLASS="verbatim"># inside class Time: |
|
| |
|
| def __init__(self, hour=0, minute=0, second=0): | | def __init__(self, hour=0, minute=0, second=0): |
| Line 145: |
Line 227: |
| self.minute = minute | | self.minute = minute |
| self.second = second | | self.second = second |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>It is common for the parameters of </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>__init__</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>
| | </PRE> |
| to have the same names as the attributes. The statement</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4> self.hour = hour | | It is common for the parameters of <CODE>__init__</CODE> |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>stores the value of the parameter </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>hour</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> as an attribute
| | to have the same names as the attributes. The statement |
| of </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>self</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.</FONT></FONT></P><P><A NAME="@default1506"></A><FONT COLOR=black><FONT SIZE=3> | | <PRE CLASS="verbatim"> self.hour = hour |
| </FONT></FONT><A NAME="@default1507"></A><FONT COLOR=black><FONT SIZE=3>
| | </PRE> |
| </FONT></FONT><A NAME="@default1508"></A><FONT COLOR=black><FONT SIZE=3>
| | stores the value of the parameter <TT>hour</TT> as an attribute |
| </FONT></FONT><A NAME="@default1509"></A></P><P><FONT COLOR=black><FONT SIZE=3>The parameters are optional, so if you call </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Time</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> with
| | of <TT>self</TT>. |
| no arguments, you get the default values.</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>>>> time = Time() | | |
| | |
| | |
| | |
| | |
| | |
| | The parameters are optional, so if you call <TT>Time</TT> with |
| | no arguments, you get the default values. |
| | <PRE CLASS="verbatim">>>> time = Time() |
| >>> time.print_time() | | >>> time.print_time() |
| 00:00:00 | | 00:00:00 |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>If you provide one argument, it overrides </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>hour</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>>>> time = Time (9)
| | </PRE> |
| | If you provide one argument, it overrides <TT>hour</TT>: |
| | <PRE CLASS="verbatim">>>> time = Time (9) |
| >>> time.print_time() | | >>> time.print_time() |
| 09:00:00 | | 09:00:00 |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>If you provide two arguments, they override </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>hour</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> and
| | </PRE> |
| </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>minute</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>>>> time = Time(9, 45)
| | If you provide two arguments, they override <TT>hour</TT> and |
| | <TT>minute</TT>. |
| | <PRE CLASS="verbatim">>>> time = Time(9, 45) |
| >>> time.print_time() | | >>> time.print_time() |
| 09:45:00 | | 09:45:00 |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>And if you provide three arguments, they override all three
| | </PRE> |
| default values.</FONT></FONT></P><DIV CLASS="theorem"><FONT COLOR=black><FONT SIZE=3><B>Exercise 2</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>  <EM> | | And if you provide three arguments, they override all three |
| </EM></FONT></FONT><A NAME="@default1510"></A><FONT COLOR=black><FONT SIZE=3><EM>
| | default values. |
| </EM></FONT></FONT><A NAME="@default1511"></A><P><FONT COLOR=black><FONT SIZE=3><EM>Write an init method for the </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>Point</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> class that takes
| | <DIV CLASS="theorem">'''Exercise 2'''  '' |
| </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>x</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> and </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>y</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> as optional parameters and assigns
| | '''' |
| | '' |
| | ''Write an init method for the ''''<TT>Point</TT>'''' class that takes |
| | ''''<TT>x</TT>'''' and ''''<TT>y</TT>'''' as optional parameters and assigns |
| them to the corresponding attributes. | | them to the corresponding attributes. |
| </EM></FONT></FONT></P></DIV><H2 CLASS="section"><A NAME="toc186"></A><A NAME="htoc205"><FONT COLOR=black><FONT SIZE=3>17.6</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>  The </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>__str__</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> method</FONT></FONT></H2><P><A NAME="@default1512"></A><FONT COLOR=black><FONT SIZE=3>
| | '' |
| </FONT></FONT><A NAME="@default1513"></A></P><P><CODE><FONT COLOR=black><FONT SIZE=3>__str__</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> is a special method, like </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>__init__</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>,
| | </DIV>=== 17.6  The <TT>__str__</TT> method === |
| that is supposed to return a string representation of an object.</FONT></FONT></P><P><A NAME="@default1514"></A></P><P><FONT COLOR=black><FONT SIZE=3>For example, here is a </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>str</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> method for Time objects:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4># inside class Time: | | |
| | |
| | |
| | |
| | <CODE>__str__</CODE> is a special method, like <CODE>__init__</CODE>, |
| | that is supposed to return a string representation of an object. |
| | |
| | For example, here is a <TT>str</TT> method for Time objects: |
| | <PRE CLASS="verbatim"># inside class Time: |
|
| |
|
| def __str__(self): | | def __str__(self): |
| return '%.2d:%.2d:%.2d' % (self.hour, self.minute, self.second) | | return '%.2d:%.2d:%.2d' % (self.hour, self.minute, self.second) |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>When you </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>print</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> an object, Python invokes the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>str</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> method:</FONT></FONT></P><P><A NAME="@default1515"></A><FONT COLOR=black><FONT SIZE=3>
| | </PRE> |
| </FONT></FONT><A NAME="@default1516"></A></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>>>> time = Time(9, 45)
| | When you <TT>print</TT> an object, Python invokes the <TT>str</TT> method: |
| | |
| | |
| | |
| | <PRE CLASS="verbatim">>>> time = Time(9, 45) |
| >>> print time | | >>> print time |
| 09:45:00 | | 09:45:00 |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>When I write a new class, I almost always start by writing
| | </PRE> |
| </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>__init__</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>, which makes it easier to instantiate objects, and
| | When I write a new class, I almost always start by writing |
| </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>__str__</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>, which is useful for debugging.</FONT></FONT></P><DIV CLASS="theorem"><FONT COLOR=black><FONT SIZE=3><B>Exercise 3</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>  <EM>
| | <CODE>__init__</CODE>, which makes it easier to instantiate objects, and |
| Write a </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>str</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> method for the </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>Point</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> class. Create | | <CODE>__str__</CODE>, which is useful for debugging. |
| | <DIV CLASS="theorem">'''Exercise 3'''  '' |
| | Write a ''''<TT>str</TT>'''' method for the ''''<TT>Point</TT>'''' class. Create |
| a Point object and print it. | | a Point object and print it. |
| </EM></FONT></FONT></DIV><H2 CLASS="section"><A NAME="toc187"></A><A NAME="htoc206"><FONT COLOR=black><FONT SIZE=3>17.7</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>  Operator overloading</FONT></FONT></H2><P><FONT COLOR=black><FONT SIZE=3>
| | ''</DIV>=== 17.7  Operator overloading === |
| </FONT></FONT><A NAME="operator overloading"></A></P><P><FONT COLOR=black><FONT SIZE=3>By defining other special methods, you can specify the behavior
| | |
| | |
| | |
| | |
| | By defining other special methods, you can specify the behavior |
| of operators on user-defined types. For example, if you define | | of operators on user-defined types. For example, if you define |
| a method named </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>__add__</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> for the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>Time</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> class, you can use the | | a method named <CODE>__add__</CODE> for the <TT>Time</TT> class, you can use the |
| </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>+</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> operator on Time objects.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>Here is what the definition might look like:</FONT></FONT></P><P><A NAME="@default1517"></A><FONT COLOR=black><FONT SIZE=3>
| | <TT>+</TT> operator on Time objects. |
| </FONT></FONT><A NAME="@default1518"></A></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4># inside class Time:
| | |
| | Here is what the definition might look like: |
| | |
| | |
| | |
| | <PRE CLASS="verbatim"># inside class Time: |
|
| |
|
| def __add__(self, other): | | def __add__(self, other): |
| seconds = self.time_to_int() + other.time_to_int() | | seconds = self.time_to_int() + other.time_to_int() |
| return int_to_time(seconds) | | return int_to_time(seconds) |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>And here is how you could use it:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>>>> start = Time(9, 45)
| | </PRE> |
| | And here is how you could use it: |
| | <PRE CLASS="verbatim">>>> start = Time(9, 45) |
| >>> duration = Time(1, 35) | | >>> duration = Time(1, 35) |
| >>> print start + duration | | >>> print start + duration |
| 11:20:00 | | 11:20:00 |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>When you apply the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>+</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> operator to Time objects, Python invokes
| | </PRE> |
| </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>__add__</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>. When you print the result, Python invokes
| | When you apply the <TT>+</TT> operator to Time objects, Python invokes |
| </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>__str__</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>. So there is quite a lot happening behind the scenes!</FONT></FONT></P><P><A NAME="@default1519"></A></P><P><FONT COLOR=black><FONT SIZE=3>Changing the behavior of an operator so that it works with
| | <CODE>__add__</CODE>. When you print the result, Python invokes |
| user-defined types is called </FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>operator overloading</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>. For every | | <CODE>__str__</CODE>. So there is quite a lot happening behind the scenes! |
| | |
| | Changing the behavior of an operator so that it works with |
| | user-defined types is called '''operator overloading'''. For every |
| operator in Python there is a corresponding special method, like | | operator in Python there is a corresponding special method, like |
| </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>__add__</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>. For more details, see
| | <CODE>__add__</CODE>. For more details, see |
| </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>docs.python.org/ref/specialnames.html</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.</FONT></FONT></P><DIV CLASS="theorem"><FONT COLOR=black><FONT SIZE=3><B>Exercise 4</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>  <EM>
| | <TT>docs.python.org/ref/specialnames.html</TT>. |
| Write an </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>add</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> method for the Point class. | | <DIV CLASS="theorem">'''Exercise 4'''  '' |
| </EM></FONT></FONT></DIV><H2 CLASS="section"><A NAME="toc188"></A><A NAME="htoc207"><FONT COLOR=black><FONT SIZE=3>17.8</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>  Type-based dispatch</FONT></FONT></H2><P><FONT COLOR=black><FONT SIZE=3>In the previous section we added two Time objects, but you
| | Write an ''''<TT>add</TT>'''' method for the Point class. |
| | ''</DIV>=== 17.8  Type-based dispatch === |
| | |
| | In the previous section we added two Time objects, but you |
| also might want to add an integer to a Time object. The | | also might want to add an integer to a Time object. The |
| following is a version of </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>__add__</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> | | following is a version of <CODE>__add__</CODE> |
| that checks the type of </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>other</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> and invokes either | | that checks the type of <TT>other</TT> and invokes either |
| </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>add_time</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> or </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>increment</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4># inside class Time:
| | <CODE>add_time</CODE> or <TT>increment</TT>: |
| | <PRE CLASS="verbatim"># inside class Time: |
|
| |
|
| def __add__(self, other): | | def __add__(self, other): |
| Line 224: |
Line 353: |
| seconds += self.time_to_int() | | seconds += self.time_to_int() |
| return int_to_time(seconds) | | return int_to_time(seconds) |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>The built-in function </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>isinstance</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> takes a value and a
| | </PRE> |
| class object, and returns </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>True</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> if the value is an instance | | The built-in function <TT>isinstance</TT> takes a value and a |
| of the class.</FONT></FONT></P><P><A NAME="@default1520"></A><FONT COLOR=black><FONT SIZE=3> | | class object, and returns <TT>True</TT> if the value is an instance |
| </FONT></FONT><A NAME="@default1521"></A></P><P><FONT COLOR=black><FONT SIZE=3>If </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>other</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> is a Time object, </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>__add__</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> invokes
| | of the class. |
| </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>add_time</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>. Otherwise it assumes that the parameter
| | |
| is a number and invokes </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>increment</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>. This operation is | | |
| called a </FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>type-based dispatch</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3> because it dispatches the | | |
| | |
| | If <TT>other</TT> is a Time object, <CODE>__add__</CODE> invokes |
| | <CODE>add_time</CODE>. Otherwise it assumes that the parameter |
| | is a number and invokes <TT>increment</TT>. This operation is |
| | called a '''type-based dispatch''' because it dispatches the |
| computation to different methods based on the type of the | | computation to different methods based on the type of the |
| arguments.</FONT></FONT></P><P><A NAME="@default1522"></A><FONT COLOR=black><FONT SIZE=3> | | arguments. |
| </FONT></FONT><A NAME="@default1523"></A></P><P><FONT COLOR=black><FONT SIZE=3>Here are examples that use the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>+</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> operator with different
| | |
| types:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>>>> start = Time(9, 45) | | |
| | |
| | |
| | Here are examples that use the <TT>+</TT> operator with different |
| | types: |
| | <PRE CLASS="verbatim">>>> start = Time(9, 45) |
| >>> duration = Time(1, 35) | | >>> duration = Time(1, 35) |
| >>> print start + duration | | >>> print start + duration |
| Line 240: |
Line 379: |
| >>> print start + 1337 | | >>> print start + 1337 |
| 10:07:17 | | 10:07:17 |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>Unfortunately, this implementation of addition is not commutative.
| | </PRE> |
| If the integer is the first operand, you get</FONT></FONT></P><P><A NAME="@default1524"></A></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>>>> print 1337 + start | | Unfortunately, this implementation of addition is not commutative. |
| | If the integer is the first operand, you get |
| | |
| | <PRE CLASS="verbatim">>>> print 1337 + start |
| TypeError: unsupported operand type(s) for +: 'int' and 'instance' | | TypeError: unsupported operand type(s) for +: 'int' and 'instance' |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>The problem is, instead of asking the Time object to add an integer,
| | </PRE> |
| | The problem is, instead of asking the Time object to add an integer, |
| Python is asking an integer to add a Time object, and it doesn’t know | | Python is asking an integer to add a Time object, and it doesn’t know |
| how to do that. But there is a clever solution for this problem: the | | how to do that. But there is a clever solution for this problem: the |
| special method </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>__radd__</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>, which stands for “right-side add.” | | special method <CODE>__radd__</CODE>, which stands for “right-side add.” |
| This method is invoked when a Time object appears on the right side of | | This method is invoked when a Time object appears on the right side of |
| the </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>+</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> operator. Here’s the definition:</FONT></FONT></P><P><A NAME="@default1525"></A><FONT COLOR=black><FONT SIZE=3> | | the <TT>+</TT> operator. Here’s the definition: |
| </FONT></FONT><A NAME="@default1526"></A></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4># inside class Time:
| | |
| | |
| | |
| | <PRE CLASS="verbatim"># inside class Time: |
|
| |
|
| def __radd__(self, other): | | def __radd__(self, other): |
| return self.__add__(other) | | return self.__add__(other) |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>And here’s how it’s used:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>>>> print 1337 + start
| | </PRE> |
| | And here’s how it’s used: |
| | <PRE CLASS="verbatim">>>> print 1337 + start |
| 10:07:17 | | 10:07:17 |
| </FONT></FONT></PRE><DIV CLASS="theorem"><FONT COLOR=black><FONT SIZE=3><B>Exercise 5</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>  <EM>
| | </PRE><DIV CLASS="theorem">'''Exercise 5'''  '' |
| Write an </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>add</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> method for Points that works with either a | | Write an ''''<TT>add</TT>'''' method for Points that works with either a |
| Point object or a tuple: </EM></FONT></FONT><UL CLASS="itemize"><LI CLASS="li-itemize"><FONT COLOR=black><FONT SIZE=3><EM>If the second operand is a Point, the method should return a new | | Point object or a tuple: '' |
| Point whose </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><I>x</I></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> coordinate is the sum of the </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><I>x</I></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> coordinates of the | | |
| operands, and likewise for the </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><I>y</I></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> coordinates.</EM></FONT></FONT></LI><LI CLASS="li-itemize"><FONT COLOR=black><FONT SIZE=3><EM>If the second operand is a tuple, the method should add the | | *''If the second operand is a Point, the method should return a new |
| first element of the tuple to the </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><I>x</I></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> coordinate and the second | | Point whose ''''<I>x</I>'''' coordinate is the sum of the ''''<I>x</I>'''' coordinates of the |
| element to the </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><I>y</I></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> coordinate, and return a new Point with the result. </EM></FONT></FONT></LI></UL></DIV><H2 CLASS="section"><A NAME="toc189"></A><A NAME="htoc208"><FONT COLOR=black><FONT SIZE=3>17.9</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>  Polymorphism</FONT></FONT></H2><P><FONT COLOR=black><FONT SIZE=3>Type-based dispatch is useful when it is necessary, but (fortunately) | | operands, and likewise for the ''''<I>y</I>'''' coordinates.'' |
| | |
| | *''If the second operand is a tuple, the method should add the |
| | first element of the tuple to the ''''<I>x</I>'''' coordinate and the second |
| | element to the ''''<I>y</I>'''' coordinate, and return a new Point with the result. '' |
| | |
| | </DIV>=== 17.9  Polymorphism === |
| | |
| | Type-based dispatch is useful when it is necessary, but (fortunately) |
| it is not always necessary. Often you can avoid it by writing functions | | it is not always necessary. Often you can avoid it by writing functions |
| that work correctly for arguments with different types.</FONT></FONT></P><P><A NAME="@default1527"></A><FONT COLOR=black><FONT SIZE=3> | | that work correctly for arguments with different types. |
| </FONT></FONT><A NAME="@default1528"></A></P><P><FONT COLOR=black><FONT SIZE=3>Many of the functions we wrote for strings will actually
| | |
| | |
| | |
| | |
| | Many of the functions we wrote for strings will actually |
| work for any kind of sequence. | | work for any kind of sequence. |
| For example, in Section </FONT></FONT><A HREF="book012.html#histogram"><FONT COLOR=black><FONT SIZE=3>11.1</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3> | | For example, in Section 11.1 |
| we used </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>histogram</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> to count the number of times each letter | | we used <TT>histogram</TT> to count the number of times each letter |
| appears in a word.</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>def histogram(s): | | appears in a word. |
| | <PRE CLASS="verbatim">def histogram(s): |
| d = dict() | | d = dict() |
| for c in s: | | for c in s: |
| Line 276: |
Line 437: |
| d[c] = d[c]+1 | | d[c] = d[c]+1 |
| return d | | return d |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>This function also works for lists, tuples, and even dictionaries,
| | </PRE> |
| as long as the elements of </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>s</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> are hashable, so they can be used | | This function also works for lists, tuples, and even dictionaries, |
| as keys in </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>d</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>>>> t = ['spam', 'egg', 'spam', 'spam', 'bacon', 'spam'] | | as long as the elements of <TT>s</TT> are hashable, so they can be used |
| | as keys in <TT>d</TT>. |
| | <PRE CLASS="verbatim">>>> t = ['spam', 'egg', 'spam', 'spam', 'bacon', 'spam'] |
| >>> histogram(t) | | >>> histogram(t) |
| {'bacon': 1, 'egg': 1, 'spam': 4} | | {'bacon': 1, 'egg': 1, 'spam': 4} |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>Functions that can work with several types are called </FONT></FONT><FONT COLOR=black><FONT SIZE=3><B>polymorphic</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>.
| | </PRE> |
| | Functions that can work with several types are called '''polymorphic'''. |
| Polymorphism can facilitate code reuse. For example, the built-in | | Polymorphism can facilitate code reuse. For example, the built-in |
| function </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>sum</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>, which adds the elements of a sequence, works | | function <TT>sum</TT>, which adds the elements of a sequence, works |
| as long as the elements of the sequence support addition.</FONT></FONT></P><P><A NAME="@default1529"></A></P><P><FONT COLOR=black><FONT SIZE=3>Since Time objects provide an </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>add</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> method, they work | | as long as the elements of the sequence support addition. |
| with </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>sum</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3>:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>>>> t1 = Time(7, 43) | | |
| | Since Time objects provide an <TT>add</TT> method, they work |
| | with <TT>sum</TT>: |
| | <PRE CLASS="verbatim">>>> t1 = Time(7, 43) |
| >>> t2 = Time(7, 41) | | >>> t2 = Time(7, 41) |
| >>> t3 = Time(7, 37) | | >>> t3 = Time(7, 37) |
| Line 291: |
Line 458: |
| >>> print total | | >>> print total |
| 23:01:00 | | 23:01:00 |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>In general, if all of the operations inside a function
| | </PRE> |
| work with a given type, then the function works with that type.</FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3>The best kind of polymorphism is the unintentional kind, where | | In general, if all of the operations inside a function |
| | work with a given type, then the function works with that type. |
| | |
| | The best kind of polymorphism is the unintentional kind, where |
| you discover that a function you already wrote can be | | you discover that a function you already wrote can be |
| applied to a type you never planned for.</FONT></FONT></P><H2 CLASS="section"><A NAME="toc190"></A><A NAME="htoc209"><FONT COLOR=black><FONT SIZE=3>17.10</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>  Debugging</FONT></FONT></H2><P><FONT COLOR=black><FONT SIZE=3> | | applied to a type you never planned for. |
| </FONT></FONT><A NAME="@default1530"></A></P><P><FONT COLOR=black><FONT SIZE=3>It is legal to add attributes to objects at any point in the execution
| | === 17.10  Debugging === |
| | |
| | |
| | |
| | |
| | It is legal to add attributes to objects at any point in the execution |
| of a program, but if you are a stickler for type theory, it is a | | of a program, but if you are a stickler for type theory, it is a |
| dubious practice to have objects of the same type with different | | dubious practice to have objects of the same type with different |
| attribute sets. It is usually a good idea to | | attribute sets. It is usually a good idea to |
| initialize all of an objects attributes in the init method.</FONT></FONT></P><P><A NAME="@default1531"></A><FONT COLOR=black><FONT SIZE=3> | | initialize all of an objects attributes in the init method. |
| </FONT></FONT><A NAME="@default1532"></A></P><P><FONT COLOR=black><FONT SIZE=3>If you are not sure whether an object has a particular attribute, 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> (see Section </FONT></FONT><A HREF="book016.html#hasattr"><FONT COLOR=black><FONT SIZE=3>15.7</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>).</FONT></FONT></P><P><A NAME="@default1533"></A><FONT COLOR=black><FONT SIZE=3> | | |
| </FONT></FONT><A NAME="@default1534"></A><FONT COLOR=black><FONT SIZE=3>
| | |
| </FONT></FONT><A NAME="@default1535"></A><FONT COLOR=black><FONT SIZE=3>
| | |
| </FONT></FONT><A NAME="@default1536"></A></P><P><FONT COLOR=black><FONT SIZE=3>Another way to access the attributes of an object is through the
| | If you are not sure whether an object has a particular attribute, you |
| special attribute </FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3>__dict__</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3>, which is a dictionary that maps | | can use the built-in function <TT>hasattr</TT> (see Section 15.7). |
| attribute names (as strings) and values:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>>>> p = Point(3, 4) | | |
| | |
| | |
| | |
| | |
| | |
| | Another way to access the attributes of an object is through the |
| | special attribute <CODE>__dict__</CODE>, which is a dictionary that maps |
| | attribute names (as strings) and values: |
| | <PRE CLASS="verbatim">>>> p = Point(3, 4) |
| >>> print p.__dict__ | | >>> print p.__dict__ |
| {'y': 4, 'x': 3} | | {'y': 4, 'x': 3} |
| </FONT></FONT></PRE><P><FONT COLOR=black><FONT SIZE=3>For purposes of debugging, you might find it useful to keep this
| | </PRE> |
| function handy:</FONT></FONT></P><PRE CLASS="verbatim"><FONT COLOR=blue><FONT SIZE=4>def print_attributes(obj): | | For purposes of debugging, you might find it useful to keep this |
| | function handy: |
| | <PRE CLASS="verbatim">def print_attributes(obj): |
| for attr in obj.__dict__: | | for attr in obj.__dict__: |
| print attr, getattr(obj, attr) | | print attr, getattr(obj, attr) |
| </FONT></FONT></PRE><P><CODE><FONT COLOR=black><FONT SIZE=3>print_attributes</FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3> traverses the items in the object’s dictionary
| | </PRE> |
| and prints each attribute name and its corresponding value.</FONT></FONT></P><P><A NAME="@default1537"></A><FONT COLOR=black><FONT SIZE=3> | | <CODE>print_attributes</CODE> traverses the items in the object’s dictionary |
| </FONT></FONT><A NAME="@default1538"></A></P><P><FONT COLOR=black><FONT SIZE=3>The built-in function </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>getattr</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> takes an object and an attribute
| | and prints each attribute name and its corresponding value. |
| name (as a string) and returns the attribute’s value.</FONT></FONT></P><P><A NAME="@default1539"></A><FONT COLOR=black><FONT SIZE=3> | | |
| </FONT></FONT><A NAME="@default1540"></A></P><H2 CLASS="section"><A NAME="toc191"></A><A NAME="htoc210"><FONT COLOR=black><FONT SIZE=3>17.11</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>  Glossary</FONT></FONT></H2><DL CLASS="description"><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>object-oriented language:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> A language that provides features,
| | |
| | |
| | |
| | The built-in function <TT>getattr</TT> takes an object and an attribute |
| | name (as a string) and returns the attribute’s value. |
| | |
| | |
| | |
| | === 17.11  Glossary === |
| | |
| | <DL CLASS="description"><DT CLASS="dt-description">'''object-oriented language:'''</DT><DD CLASS="dd-description"> A language that provides features, |
| such as user-defined classes and method syntax, that facilitate | | such as user-defined classes and method syntax, that facilitate |
| object-oriented programming. | | object-oriented programming. |
| </FONT></FONT><A NAME="@default1541"></A></DD><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>object-oriented programming:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> A style of programming in which
| | </DD><DT CLASS="dt-description">'''object-oriented programming:'''</DT><DD CLASS="dd-description"> A style of programming in which |
| data and the operations that manipulate it are organized into classes | | data and the operations that manipulate it are organized into classes |
| and methods. | | and methods. |
| </FONT></FONT><A NAME="@default1542"></A></DD><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>method:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> A function that is defined inside a class definition and
| | </DD><DT CLASS="dt-description">'''method:'''</DT><DD CLASS="dd-description"> A function that is defined inside a class definition and |
| is invoked on instances of that class. | | is invoked on instances of that class. |
| </FONT></FONT><A NAME="@default1543"></A></DD><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>subject:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> The object a method is invoked on.
| | </DD><DT CLASS="dt-description">'''subject:'''</DT><DD CLASS="dd-description"> The object a method is invoked on. |
| </FONT></FONT><A NAME="@default1544"></A></DD><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>operator overloading:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> Changing the behavior of an operator like
| | </DD><DT CLASS="dt-description">'''operator overloading:'''</DT><DD CLASS="dd-description"> Changing the behavior of an operator like |
| </FONT></FONT><FONT COLOR=black><FONT SIZE=3><TT>+</TT></FONT></FONT><FONT COLOR=black><FONT SIZE=3> so it works with a user-defined type.
| | <TT>+</TT> so it works with a user-defined type. |
| </FONT></FONT><A NAME="@default1545"></A><FONT COLOR=black><FONT SIZE=3>
| | |
| </FONT></FONT><A NAME="@default1546"></A></DD><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>type-based dispatch:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> A programming pattern that checks the type
| | </DD><DT CLASS="dt-description">'''type-based dispatch:'''</DT><DD CLASS="dd-description"> A programming pattern that checks the type |
| of an operand and invokes different functions for different types. | | of an operand and invokes different functions for different types. |
| </FONT></FONT><A NAME="@default1547"></A></DD><DT CLASS="dt-description"><FONT COLOR=black><FONT SIZE=3><B>polymorphic:</B></FONT></FONT></DT><DD CLASS="dd-description"><FONT COLOR=black><FONT SIZE=3> Pertaining to a function that can work with more
| | </DD><DT CLASS="dt-description">'''polymorphic:'''</DT><DD CLASS="dd-description"> Pertaining to a function that can work with more |
| than one type. </FONT></FONT><P><A NAME="@default1548"></A></P></DD></DL><H2 CLASS="section"><A NAME="toc192"></A><A NAME="htoc211"><FONT COLOR=black><FONT SIZE=3>17.12</FONT></FONT></A><FONT COLOR=black><FONT SIZE=3>  Exercises</FONT></FONT></H2><DIV CLASS="theorem"><FONT COLOR=black><FONT SIZE=3><B>Exercise 6</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>  </FONT></FONT><P><A NAME="@default1549"></A><FONT COLOR=black><FONT SIZE=3><EM> | | than one type. |
| </EM></FONT></FONT><A NAME="@default1550"></A><FONT COLOR=black><FONT SIZE=3><EM>
| | |
| </EM></FONT></FONT><A NAME="@default1551"></A><FONT COLOR=black><FONT SIZE=3><EM>
| | </DD></DL>=== 17.12  Exercises === |
| </EM></FONT></FONT><A NAME="@default1552"></A></P><P><FONT COLOR=black><FONT SIZE=3><EM>This exercise is a cautionary tale about one of the most
| | |
| common, and difficult to find, errors in Python.</EM></FONT></FONT></P><OL CLASS="enumerate" type=1><LI CLASS="li-enumerate"><P><A NAME="@default1553"></A><FONT COLOR=black><FONT SIZE=3><EM> | | <DIV CLASS="theorem">'''Exercise 6'''   |
| </EM></FONT></FONT><A NAME="@default1554"></A></P><FONT COLOR=black><FONT SIZE=3><EM>Write a definition for a class named </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>Kangaroo</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM> with the following
| | '' |
| methods:</EM></FONT></FONT><OL CLASS="enumerate" type=a><LI CLASS="li-enumerate"><FONT COLOR=black><FONT SIZE=3><EM>An </EM></FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3><EM>__init__</EM></FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3><EM> method that initializes an attribute named | | '''' |
| </EM></FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3><EM>pouch_contents</EM></FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3><EM> to an empty list.</EM></FONT></FONT></LI><LI CLASS="li-enumerate"><FONT COLOR=black><FONT SIZE=3><EM>A method named </EM></FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3><EM>put_in_pouch</EM></FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3><EM> that takes an object
| | '''' |
| of any type and adds it to </EM></FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3><EM>pouch_contents</EM></FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3><EM>.</EM></FONT></FONT></LI><LI CLASS="li-enumerate"><FONT COLOR=black><FONT SIZE=3><EM>A </EM></FONT></FONT><CODE><FONT COLOR=black><FONT SIZE=3><EM>__str__</EM></FONT></FONT></CODE><FONT COLOR=black><FONT SIZE=3><EM> method that returns a string representation | | '' |
| of the Kangaroo object and the contents of the pouch.</EM></FONT></FONT></LI></OL><P><EM><FONT COLOR=black><FONT SIZE=3><EM> | | |
| | ''This exercise is a cautionary tale about one of the most |
| | common, and difficult to find, errors in Python.'' |
| | |
| | * |
| | '' |
| | '' |
| | ''Write a definition for a class named ''''<TT>Kangaroo</TT>'''' with the following |
| | methods:'' |
| | |
| | *''An ''<CODE>''__init__''</CODE>'' method that initializes an attribute named |
| | ''<CODE>''pouch_contents''</CODE>'' to an empty list.'' |
| | |
| | *''A method named ''<CODE>''put_in_pouch''</CODE>'' that takes an object |
| | of any type and adds it to ''<CODE>''pouch_contents''</CODE>''.'' |
| | |
| | *''A ''<CODE>''__str__''</CODE>'' method that returns a string representation |
| | of the Kangaroo object and the contents of the pouch.'' |
| | |
| | '''' |
| Test your code | | Test your code |
| by creating two </EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM><TT>Kangaroo</TT></EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM> objects, assigning them to variables | | by creating two ''''''''<TT>Kangaroo</TT>'''''''' objects, assigning them to variables |
| named </EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM><TT>kanga</TT></EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM> and </EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM><TT>roo</TT></EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM>, and then adding </EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM><TT>roo</TT></EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM> to the | | named ''''''''<TT>kanga</TT>'''''''' and ''''''''<TT>roo</TT>'''''''', and then adding ''''''''<TT>roo</TT>'''''''' to the |
| contents of </EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM><TT>kanga</TT></EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM>’s pouch.</EM></FONT></FONT></EM></P></LI><LI CLASS="li-enumerate"><EM><FONT COLOR=black><FONT SIZE=3><EM>Download </EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM><TT>thinkpython.com/code/BadKangaroo.py</TT></EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM>. It contains | | contents of ''''''''<TT>kanga</TT>''''''''’s pouch.'''' |
| | |
| | *''''Download ''''''''<TT>thinkpython.com/code/BadKangaroo.py</TT>''''''''. It contains |
| a solution to the previous problem with one big, nasty bug. | | a solution to the previous problem with one big, nasty bug. |
| Find and fix the bug.</EM></FONT></FONT></EM><P><EM><FONT COLOR=black><FONT SIZE=3><EM>If you get stuck, you can download | | Find and fix the bug.'''' |
| </EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM><TT>thinkpython.com/code/GoodKangaroo.py</TT></EM></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><EM>, which explains the
| | ''''If you get stuck, you can download |
| problem and demonstrates a solution.</EM></FONT></FONT></EM></P><P><A NAME="@default1555"></A><EM><FONT COLOR=black><FONT SIZE=3><EM> | | ''''''''<TT>thinkpython.com/code/GoodKangaroo.py</TT>'''''''', which explains the |
| </EM></FONT></FONT></EM><A NAME="@default1556"></A><EM><FONT COLOR=black><FONT SIZE=3><EM>
| | problem and demonstrates a solution.'''' |
| </EM></FONT></FONT></EM><A NAME="@default1557"></A></P></LI></OL></DIV><DIV CLASS="theorem"><FONT COLOR=black><FONT SIZE=3><B>Exercise 7</B></FONT></FONT><FONT COLOR=black><FONT SIZE=3>  </FONT></FONT><P><A NAME="@default1558"></A><FONT COLOR=black><FONT SIZE=3><EM>
| | |
| </EM></FONT></FONT><A NAME="@default1559"></A><FONT COLOR=black><FONT SIZE=3><EM>
| | '''' |
| </EM></FONT></FONT><A NAME="@default1560"></A><FONT COLOR=black><FONT SIZE=3><EM>
| | '''''''' |
| </EM></FONT></FONT><A NAME="@default1561"></A></P><P><FONT COLOR=black><FONT SIZE=3><EM>Visual is a Python module that provides 3-D graphics. It is
| | '''' |
| | |
| | </DIV><DIV CLASS="theorem">'''Exercise 7'''   |
| | '' |
| | '''' |
| | '''' |
| | '' |
| | |
| | ''Visual is a Python module that provides 3-D graphics. It is |
| not always included in a Python installation, so you might have | | not always included in a Python installation, so you might have |
| to install it from your software repository or, if it’s not there, | | to install it from your software repository or, if it’s not there, |
| from </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM><TT>vpython.org</TT></EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>.</EM></FONT></FONT></P><P><FONT COLOR=black><FONT SIZE=3><EM>The following example creates a 3-D space that is 256 units | | from ''''<TT>vpython.org</TT>''''.'' |
| | |
| | ''The following example creates a 3-D space that is 256 units |
| wide, long and high, and sets the “center” to be the | | wide, long and high, and sets the “center” to be the |
| point </EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>(128, 128, 128)</EM></FONT></FONT><FONT COLOR=black><FONT SIZE=3><EM>. Then it draws a blue sphere.</EM></FONT></FONT></P><PRE CLASS="verbatim"><EM><FONT COLOR=blue><FONT SIZE=4>from visual import * | | point ''''(128, 128, 128)''''. Then it draws a blue sphere.'' |
| | <PRE CLASS="verbatim">''from visual import * |
|
| |
|
| scene.range = (256, 256, 256) | | scene.range = (256, 256, 256) |
| Line 366: |
Line 594: |
| color = (0.1, 0.1, 0.9) # mostly blue | | color = (0.1, 0.1, 0.9) # mostly blue |
| sphere(pos=scene.center, radius=128, color=color) | | sphere(pos=scene.center, radius=128, color=color) |
| </FONT></FONT></EM></PRE><P><EM><FONT COLOR=black><FONT SIZE=3><TT>color</TT></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3> is an RGB tuple; that is, the elements are Red-Green-Blue
| | ''</PRE> |
| | ''<TT>color</TT>'''' is an RGB tuple; that is, the elements are Red-Green-Blue |
| levels between 0.0 and 1.0 (see | | levels between 0.0 and 1.0 (see |
| </FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><TT>wikipedia.org/wiki/RGB_color_model</TT></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3>).</FONT></FONT></EM></P><P><EM><FONT COLOR=black><FONT SIZE=3>If you run this code, you should see a window with a black
| | ''''<TT>wikipedia.org/wiki/RGB_color_model</TT>'''').'' |
| | |
| | ''If you run this code, you should see a window with a black |
| background and a blue sphere. If you drag the middle button | | background and a blue sphere. If you drag the middle button |
| up and down, you can zoom in and out. You can also rotate | | up and down, you can zoom in and out. You can also rotate |
| the scene by dragging the right button, but with only one | | the scene by dragging the right button, but with only one |
| sphere in the world, it is hard to tell the difference.</FONT></FONT></EM></P><P><EM><FONT COLOR=black><FONT SIZE=3>The following loop creates a cube of spheres:</FONT></FONT></EM></P><PRE CLASS="verbatim"><EM><FONT COLOR=blue><FONT SIZE=4>t = range(0, 256, 51) | | sphere in the world, it is hard to tell the difference.'' |
| | |
| | ''The following loop creates a cube of spheres:'' |
| | <PRE CLASS="verbatim">''t = range(0, 256, 51) |
| for x in t: | | for x in t: |
| for y in t: | | for y in t: |
| Line 378: |
Line 612: |
| pos = x, y, z | | pos = x, y, z |
| sphere(pos=pos, radius=10, color=color) | | sphere(pos=pos, radius=10, color=color) |
| </FONT></FONT></EM></PRE><OL CLASS="enumerate" type=1><LI CLASS="li-enumerate"><EM><FONT COLOR=black><FONT SIZE=3>Put this code in a script and make sure it works for
| | ''</PRE> |
| you.</FONT></FONT></EM></LI><LI CLASS="li-enumerate"><EM><FONT COLOR=black><FONT SIZE=3>Modify the program so that each sphere in the cube | | |
| | *''Put this code in a script and make sure it works for |
| | you.'' |
| | |
| | *''Modify the program so that each sphere in the cube |
| has the color that corresponds to its position in RGB space. | | has the color that corresponds to its position in RGB space. |
| Notice that the coordinates are in the range 0–255, but | | Notice that the coordinates are in the range 0–255, but |
| the RGB tuples are in the range 0.0–1.0.</FONT></FONT></EM><P><A NAME="@default1562"></A><EM><FONT COLOR=black><FONT SIZE=3> | | the RGB tuples are in the range 0.0–1.0.'' |
| </FONT></FONT></EM><A NAME="@default1563"></A></P></LI><LI CLASS="li-enumerate"><EM><FONT COLOR=black><FONT SIZE=3>Download </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>
| | '' |
| and use the function </FONT></FONT></EM><CODE><EM><FONT COLOR=black><FONT SIZE=3>read_colors</FONT></FONT></EM></CODE><EM><FONT COLOR=black><FONT SIZE=3> to generate a list | | '' |
| | |
| | *''Download ''''<TT>thinkpython.com/code/color_list.py</TT>'''' |
| | and use the function ''<CODE>''read_colors''</CODE>'' to generate a list |
| of the available colors on your system, their names and | | of the available colors on your system, their names and |
| RGB values. For each named color draw a sphere in the | | RGB values. For each named color draw a sphere in the |
| position that corresponds to its RGB values.</FONT></FONT></EM></LI></OL><P><EM><FONT COLOR=black><FONT SIZE=3>You can see my solution at </FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3><TT>thinkpython.com/code/color_space.py</TT></FONT></FONT></EM><EM><FONT COLOR=black><FONT SIZE=3>.</FONT></FONT></EM></P></DIV><HR> | | position that corresponds to its RGB values.'' |
| <A HREF="book017.html"><IMG SRC="previous_motif.gif" ALT="Previous"></A>
| | |
| <A HREF="index.html"><IMG SRC="contents_motif.gif" ALT="Up"></A>
| | ''You can see my solution at ''''<TT>thinkpython.com/code/color_space.py</TT>''''.'' |
| <A HREF="book019.html"><IMG SRC="next_motif.gif" ALT="Next"></A>
| | </DIV><HR> |
| </BODY>
| | <IMG SRC="previous_motif.gif" ALT="Previous"> |
| </HTML>
| | <IMG SRC="contents_motif.gif" ALT="Up"> |
| | <IMG SRC="next_motif.gif" ALT="Next"> |