Archive:Think Python/Debugging: Difference between revisions
wikademia>Whiteknight m Think Python: Automatically uploading HTML source of this book from http://www.greenteapress.com/thinkpython/html/. Will convert to wikitext in a separate step |
wikademia>Wikademia |
||
| (2 intermediate revisions by 2 users not shown) | |||
| Line 1: | Line 1: | ||
{{Think Python/Page}} | |||
== Appendix A  Debugging == | |||
Different kinds of errors can occur | |||
in a program, and it is useful to distinguish among them | in a program, and it is useful to distinguish among them | ||
in order to track them down more quickly: | in order to track them down more quickly: | ||
*Syntax errors are produced by Python when it is translating the | |||
source code into byte code. They usually indicate that there is | source code into byte code. They usually indicate that there is | ||
something wrong with the syntax of the program. Example: Omitting | something wrong with the syntax of the program. Example: Omitting | ||
the colon at the end of a | the colon at the end of a <TT>def</TT> statement yields the somewhat | ||
redundant message | redundant message <TT>SyntaxError: invalid syntax</TT>. | ||
*Runtime errors are produced by the interpreter if something goes | |||
wrong while the program is running. Most runtime error messages | wrong while the program is running. Most runtime error messages | ||
include information about where the error occurred and what | include information about where the error occurred and what | ||
functions were executing. Example: An infinite recursion eventually | functions were executing. Example: An infinite recursion eventually | ||
causes the runtime error “maximum recursion depth exceeded.” | causes the runtime error “maximum recursion depth exceeded.” | ||
*Semantic errors are problems with a program that runs without | |||
producing error messages but doesn’t do the right thing. Example: | producing error messages but doesn’t do the right thing. Example: | ||
An expression may not be evaluated in the order you expect, yielding | An expression may not be evaluated in the order you expect, yielding | ||
an incorrect result. | an incorrect result. | ||
The first step in debugging is to figure out which kind of | |||
error you are dealing with. Although the following sections are | error you are dealing with. Although the following sections are | ||
organized by error type, some techniques are | organized by error type, some techniques are | ||
applicable in more than one situation. | applicable in more than one situation. | ||
=== A.1  Syntax errors === | |||
Syntax errors are usually easy to fix once you figure out what they | |||
are. Unfortunately, the error messages are often not helpful. | are. Unfortunately, the error messages are often not helpful. | ||
The most common messages are | The most common messages are <TT>SyntaxError: invalid syntax</TT> and | ||
<TT>SyntaxError: invalid token</TT>, neither of which is very informative. | |||
On the other hand, the message does tell you where in the program the | |||
problem occurred. Actually, it tells you where Python | problem occurred. Actually, it tells you where Python | ||
noticed a problem, which is not necessarily where the error | noticed a problem, which is not necessarily where the error | ||
is. Sometimes the error is prior to the location of the error | is. Sometimes the error is prior to the location of the error | ||
message, often on the preceding line. | message, often on the preceding line. | ||
If you are building the program incrementally, you should have | |||
a good idea about where the error is. It will be in the last | a good idea about where the error is. It will be in the last | ||
line you added. | line you added. | ||
If you are copying code from a book, start by comparing | |||
your code to the book’s code very carefully. Check every character. | your code to the book’s code very carefully. Check every character. | ||
At the same time, remember that the book might be wrong, so | At the same time, remember that the book might be wrong, so | ||
if you see something that looks like a syntax error, it might be. | if you see something that looks like a syntax error, it might be. | ||
compound statement, including | |||
Here are some ways to avoid the most common syntax errors: | |||
quotation marks. | *Make sure you are not using a Python keyword for a variable name. | ||
*Check that you have a colon at the end of the header of every | |||
compound statement, including <TT>for</TT>, <TT>while</TT>, | |||
<TT>if</TT>, and <TT>def</TT> statements. | |||
*Make sure that any strings in the code have matching | |||
quotation marks. | |||
*If you have multiline strings with triple quotes (single or double), make | |||
sure you have terminated the string properly. An unterminated string | sure you have terminated the string properly. An unterminated string | ||
may cause an | may cause an <TT>invalid token</TT> error at the end of your program, | ||
or it may treat the following part of the program as a string until it | or it may treat the following part of the program as a string until it | ||
comes to the next string. In the second case, it might not produce an error | comes to the next string. In the second case, it might not produce an error | ||
message at all! | message at all! | ||
*An unclosed opening operator—<CODE>(</CODE>, <CODE>{</CODE>, or | |||
<CODE>[</CODE>—makes Python continue with the next line as part of the | |||
current statement. Generally, an error occurs almost immediately in | current statement. Generally, an error occurs almost immediately in | ||
the next line. | the next line. | ||
a conditional. | |||
*Check for the classic <TT>=</TT> instead of <TT>==</TT> inside | |||
a conditional. | |||
*Check the indentation to make sure it lines up the way it | |||
is supposed to. Python can handle space and tabs, but if you mix | is supposed to. Python can handle space and tabs, but if you mix | ||
them it can cause problems. The best way to avoid this problem | them it can cause problems. The best way to avoid this problem | ||
is to use a text editor that knows about Python and generates | is to use a text editor that knows about Python and generates | ||
consistent indentation. | consistent indentation. | ||
If nothing works, move on to the next section... | |||
==== A.1.1  I keep making changes and it makes no difference. ==== | |||
If the interpreter says there is an error and you don’t see it, that | |||
might be because you and the interpreter are not looking at the same | might be because you and the interpreter are not looking at the same | ||
code. Check your programming environment to make sure that the | code. Check your programming environment to make sure that the | ||
program you are editing is the one Python is trying to run. | program you are editing is the one Python is trying to run. | ||
If you are not sure, try putting an obvious and deliberate syntax | |||
error at the beginning of the program. Now run it again. If the | error at the beginning of the program. Now run it again. If the | ||
interpreter doesn’t find the new error, you are not running the | interpreter doesn’t find the new error, you are not running the | ||
new code. | new code. | ||
There are a few likely culprits: | |||
*You edited the file and forgot to save the changes before | |||
running it again. Some programming environments do this | running it again. Some programming environments do this | ||
for you, but some don’t. | for you, but some don’t. | ||
the old name. | |||
incorrectly. | *You changed the name of the file, but you are still running | ||
the old name. | |||
*Something in your development environment is configured | |||
incorrectly. | |||
*If you are writing a module and using <TT>import</TT>, | |||
make sure you don’t give your module the same name as one | make sure you don’t give your module the same name as one | ||
of the standard Python modules. | of the standard Python modules. | ||
that you have to restart the interpreter or use | |||
*If you are using <TT>import</TT> to read a module, remember | |||
that you have to restart the interpreter or use <TT>reload</TT> | |||
to read a modified file. If you import the module again, it | to read a modified file. If you import the module again, it | ||
doesn’t do anything. | doesn’t do anything. | ||
If you get stuck and you can’t figure out what is going on, one | |||
approach is to start again with a new program like “Hello, World!,” | approach is to start again with a new program like “Hello, World!,” | ||
and make sure you can get a known program to run. Then gradually add | and make sure you can get a known program to run. Then gradually add | ||
the pieces of the original program to the new one. | the pieces of the original program to the new one. | ||
=== A.2  Runtime errors === | |||
Once your program is syntactically correct, | |||
Python can compile it and at least start running it. What could | Python can compile it and at least start running it. What could | ||
possibly go wrong? | possibly go wrong? | ||
==== A.2.1  My program does absolutely nothing. ==== | |||
This problem is most common when your file consists of functions and | |||
classes but does not actually invoke anything to start execution. | classes but does not actually invoke anything to start execution. | ||
This may be intentional if you only plan to import this module to | This may be intentional if you only plan to import this module to | ||
supply classes and functions. | supply classes and functions. | ||
If it is not intentional, make sure that you | |||
are invoking a function to start execution, or execute one from | are invoking a function to start execution, or execute one from | ||
the interactive prompt. Also see the “Flow of Execution” section | the interactive prompt. Also see the “Flow of Execution” section | ||
below. | below. | ||
==== A.2.2  My program hangs. ==== | |||
If a program stops and seems to be doing nothing, it is “hanging.” | |||
Often that means that it is caught in an infinite loop or infinite | Often that means that it is caught in an infinite loop or infinite | ||
recursion. | recursion. | ||
problem, add a | |||
*If there is a particular loop that you suspect is the | |||
problem, add a <TT>print</TT> statement immediately before the loop that says | |||
“entering the loop” and another immediately after that says | “entering the loop” and another immediately after that says | ||
“exiting the loop.” | “exiting the loop.” | ||
Run the program. If you get the first message and not the second, | |||
you’ve got an infinite loop. Go to the “Infinite Loop” section | you’ve got an infinite loop. Go to the “Infinite Loop” section | ||
below. | below. | ||
*Most of the time, an infinite recursion will cause the program | |||
to run for a while and then produce a “RuntimeError: Maximum | to run for a while and then produce a “RuntimeError: Maximum | ||
recursion depth exceeded” error. If that happens, go to the | recursion depth exceeded” error. If that happens, go to the | ||
“Infinite Recursion” section below. | “Infinite Recursion” section below. | ||
If you are not getting this error but you suspect there is a problem | |||
with a recursive method or function, you can still use the techniques | with a recursive method or function, you can still use the techniques | ||
in the “Infinite Recursion” section. | in the “Infinite Recursion” section. | ||
loops and other recursive functions and methods. | |||
*If neither of those steps works, start testing other | |||
loops and other recursive functions and methods. | |||
*If that doesn’t work, then it is possible that | |||
you don’t understand the flow of execution in your program. | you don’t understand the flow of execution in your program. | ||
Go to the “Flow of Execution” section below. | Go to the “Flow of Execution” section below. | ||
<H4 CLASS="subsubsection">Infinite Loop</H4> | |||
what loop is causing the problem, add a | |||
If you think you have an infinite loop and you think you know | |||
what loop is causing the problem, add a <TT>print</TT> statement at | |||
the end of the loop that prints the values of the variables in | the end of the loop that prints the values of the variables in | ||
the condition and the value of the condition. | the condition and the value of the condition. | ||
For example: | |||
<PRE CLASS="verbatim">while x > 0 and y < 0 : | |||
# do something to x | # do something to x | ||
# do something to y | # do something to y | ||
| Line 130: | Line 214: | ||
print "y: ", y | print "y: ", y | ||
print "condition: ", (x > 0 and y < 0) | print "condition: ", (x > 0 and y < 0) | ||
</PRE> | |||
Now when you run the program, you will see three lines of output | |||
for each time through the loop. The last time through the | for each time through the loop. The last time through the | ||
loop, the condition should be | loop, the condition should be <TT>false</TT>. If the loop keeps | ||
going, you will be able to see the values of | going, you will be able to see the values of <TT>x</TT> and <TT>y</TT>, | ||
and you might figure out why they are not being updated correctly. | and you might figure out why they are not being updated correctly. | ||
<H4 CLASS="subsubsection">Infinite Recursion</H4> | |||
for a while and then produce a | |||
error. | |||
Most of the time, an infinite recursion will cause the program to run | |||
for a while and then produce a <TT>Maximum recursion depth exceeded</TT> | |||
error. | |||
If you suspect that a function or method is causing an infinite | |||
recursion, start by checking to make sure that there is a base case. | recursion, start by checking to make sure that there is a base case. | ||
In other words, there should be some condition that will cause the | In other words, there should be some condition that will cause the | ||
function or method to return without making a recursive invocation. | function or method to return without making a recursive invocation. | ||
If not, then you need to rethink the algorithm and identify a base | If not, then you need to rethink the algorithm and identify a base | ||
case. | case. | ||
it, add a | |||
If there is a base case but the program doesn’t seem to be reaching | |||
it, add a <TT>print</TT> statement at the beginning of the function or method | |||
that prints the parameters. Now when you run the program, you will see | that prints the parameters. Now when you run the program, you will see | ||
a few lines of output every time the function or method is invoked, | a few lines of output every time the function or method is invoked, | ||
and you will see the parameters. If the parameters are not moving | and you will see the parameters. If the parameters are not moving | ||
toward the base case, you will get some ideas about why not. | toward the base case, you will get some ideas about why not. | ||
<H4 CLASS="subsubsection">Flow of Execution</H4> | |||
your program, add | |||
function with a message like “entering function | |||
function as it is invoked. | If you are not sure how the flow of execution is moving through | ||
your program, add <TT>print</TT> statements to the beginning of each | |||
function with a message like “entering function <TT>foo</TT>,” where | |||
<TT>foo</TT> is the name of the function. | |||
Now when you run the program, it will print a trace of each | |||
function as it is invoked. | |||
==== A.2.3  When I run the program I get an exception. ==== | |||
If something goes wrong during runtime, Python | |||
prints a message that includes the name of the | prints a message that includes the name of the | ||
exception, the line of the program where the problem occurred, | exception, the line of the program where the problem occurred, | ||
and a traceback. | and a traceback. | ||
The traceback identifies the function that is currently running, | |||
and then the function that invoked it, and then the function that | and then the function that invoked it, and then the function that | ||
invoked | invoked ''that'', and so on. In other words, it traces the | ||
sequence of function invocations that got you to where you are. It | sequence of function invocations that got you to where you are. It | ||
also includes the line number in your file where each of these | also includes the line number in your file where each of these | ||
calls occurs. | calls occurs. | ||
The first step is to examine the place in the program where | |||
the error occurred and see if you can figure out what happened. | the error occurred and see if you can figure out what happened. | ||
These are some of the most common runtime errors: | These are some of the most common runtime errors: | ||
<DL CLASS="description"><DT CLASS="dt-description">'''NameError:'''</DT><DD CLASS="dd-description"> You are trying to use a variable that doesn’t | |||
exist in the current environment. | exist in the current environment. | ||
Remember that local variables are local. You | Remember that local variables are local. You | ||
cannot refer to them from outside the function where they are defined. | cannot refer to them from outside the function where they are defined. | ||
a string, list, or tuple with something other than an integer. | |||
</DD><DT CLASS="dt-description">'''TypeError:'''</DT><DD CLASS="dd-description"> There are several possible causes: | |||
*You are trying to use a value improperly. Example: indexing | |||
a string, list, or tuple with something other than an integer. | |||
*There is a mismatch between the items in a format string and | |||
the items passed for conversion. This can happen if either the number | the items passed for conversion. This can happen if either the number | ||
of items does not match or an invalid conversion is called for. | of items does not match or an invalid conversion is called for. | ||
*You are passing the wrong number of arguments to a function or method. | |||
For methods, look at the method definition and | For methods, look at the method definition and | ||
check that the first parameter is | check that the first parameter is <TT>self</TT>. Then look at the | ||
method invocation; make sure you are invoking the method on an | method invocation; make sure you are invoking the method on an | ||
object with the right type and providing the other arguments | object with the right type and providing the other arguments | ||
correctly. | correctly. | ||
using a key that the dictionary does not contain. | |||
</DD><DT CLASS="dt-description">'''KeyError:'''</DT><DD CLASS="dd-description"> You are trying to access an element of a dictionary | |||
using a key that the dictionary does not contain. | |||
</DD><DT CLASS="dt-description">'''AttributeError:'''</DT><DD CLASS="dd-description"> You are trying to access an attribute or method | |||
that does not exist. Check the spelling! You can use | that does not exist. Check the spelling! You can use | ||
<TT>dir</TT> to list the attributes that do exist. | |||
that means that it is | If an AttributeError indicates that an object has <TT>NoneType</TT>, | ||
that means that it is <TT>None</TT>. One common cause is forgetting | |||
to return a value from a function; if you get to the end of | to return a value from a function; if you get to the end of | ||
a function without hitting a | a function without hitting a <TT>return</TT> statement, it returns | ||
<TT>None</TT>. Another common cause is using the result from | |||
a list method, like | a list method, like <TT>sort</TT>, that returns <TT>None</TT>. | ||
</DD><DT CLASS="dt-description">'''IndexError:'''</DT><DD CLASS="dd-description"> The index you are using | |||
to access a list, string, or tuple is greater than | to access a list, string, or tuple is greater than | ||
its length minus one. Immediately before the site of the error, | its length minus one. Immediately before the site of the error, | ||
add a | add a <TT>print</TT> statement to display | ||
the value of the index and the length of the array. | the value of the index and the length of the array. | ||
Is the array the right size? Is the index the right value? | Is the array the right size? Is the index the right value? | ||
</DD></DL> | |||
The Python debugger (<TT>pdb</TT>) is useful for tracking down | |||
Exceptions because it allows you to examine the state of the | Exceptions because it allows you to examine the state of the | ||
program immediately before the error. You can read | program immediately before the error. You can read | ||
about | about <TT>pdb</TT> at <TT>docs.python.org/lib/module-pdb.html</TT>. | ||
output. | <H3 CLASS="subsection">A.2.4  I added so many <TT>print</TT> statements I get inundated with | ||
output.</H3> | |||
One of the problems with using <TT>print</TT> statements for debugging | |||
is that you can end up buried in output. There are two ways | is that you can end up buried in output. There are two ways | ||
to proceed: simplify the output or simplify the program. | to proceed: simplify the output or simplify the program. | ||
To simplify the output, you can remove or comment out <TT>print</TT> | |||
statements that aren’t helping, or combine them, or format | statements that aren’t helping, or combine them, or format | ||
the output so it is easier to understand. | the output so it is easier to understand. | ||
To simplify the program, there are several things you can do. First, | |||
scale down the problem the program is working on. For example, if you | scale down the problem the program is working on. For example, if you | ||
are searching a list, search a | are searching a list, search a ''small'' list. If the program takes | ||
input from the user, give it the simplest input that causes the | input from the user, give it the simplest input that causes the | ||
problem. | problem. | ||
Second, clean up the program. Remove dead code and reorganize the | |||
program to make it as easy to read as possible. For example, if you | program to make it as easy to read as possible. For example, if you | ||
suspect that the problem is in a deeply nested part of the program, | suspect that the problem is in a deeply nested part of the program, | ||
try rewriting that part with simpler structure. If you suspect a | try rewriting that part with simpler structure. If you suspect a | ||
large function, try splitting it into smaller functions and testing them | large function, try splitting it into smaller functions and testing them | ||
separately. | separately. | ||
Often the process of finding the minimal test case leads you to the | |||
bug. If you find that a program works in one situation but not in | bug. If you find that a program works in one situation but not in | ||
another, that gives you a clue about what is going on. | another, that gives you a clue about what is going on. | ||
Similarly, rewriting a piece of code can help you find subtle | |||
bugs. If you make a change that you think doesn’t affect the | bugs. If you make a change that you think doesn’t affect the | ||
program, and it does, that can tip you off. | program, and it does, that can tip you off. | ||
=== A.3  Semantic errors === | |||
In some ways, semantic errors are the hardest to debug, | |||
because the interpreter provides no information | because the interpreter provides no information | ||
about what is wrong. Only you know what the program is supposed to | about what is wrong. Only you know what the program is supposed to | ||
do. | do. | ||
The first step is to make a connection between the program | |||
text and the behavior you are seeing. You need a hypothesis | text and the behavior you are seeing. You need a hypothesis | ||
about what the program is actually doing. One of the things | about what the program is actually doing. One of the things | ||
that makes that hard is that computers run so fast. | that makes that hard is that computers run so fast. | ||
You will often wish that you could slow the program down to human | |||
speed, and with some debuggers you can. But the time it takes to | speed, and with some debuggers you can. But the time it takes to | ||
insert a few well-placed | insert a few well-placed <TT>print</TT> statements is often short compared to | ||
setting up the debugger, inserting and removing breakpoints, and | setting up the debugger, inserting and removing breakpoints, and | ||
“stepping” the program to where the error is occurring. | “stepping” the program to where the error is occurring. | ||
==== A.3.1  My program doesn’t work. ==== | |||
You should ask yourself these questions: | |||
*Is there something the program was supposed to do but | |||
which doesn’t seem to be happening? Find the section of the code | which doesn’t seem to be happening? Find the section of the code | ||
that performs that function and make sure it is executing when | that performs that function and make sure it is executing when | ||
you think it should. | you think it should. | ||
*Is something happening that shouldn’t? Find code in | |||
your program that performs that function and see if it is | your program that performs that function and see if it is | ||
executing when it shouldn’t. | executing when it shouldn’t. | ||
*Is a section of code producing an effect that is not | |||
what you expected? Make sure that you understand the code in | what you expected? Make sure that you understand the code in | ||
question, especially if it involves invocations to functions or methods in | question, especially if it involves invocations to functions or methods in | ||
other Python modules. Read the documentation for the functions you invoke. | other Python modules. Read the documentation for the functions you invoke. | ||
Try them out by writing simple test cases and checking the results. | Try them out by writing simple test cases and checking the results. | ||
In order to program, you need to have a mental model of how | |||
programs work. If you write a program that doesn’t do what you expect, | programs work. If you write a program that doesn’t do what you expect, | ||
very often the problem is not in the program; it’s in your mental | very often the problem is not in the program; it’s in your mental | ||
model. | model. | ||
The best way to correct your mental model is to break the program | |||
into its components (usually the functions and methods) and test | into its components (usually the functions and methods) and test | ||
each component independently. Once you find the discrepancy | each component independently. Once you find the discrepancy | ||
between your model and reality, you can solve the problem. | between your model and reality, you can solve the problem. | ||
Of course, you should be building and testing components as you | |||
develop the program. If you encounter a problem, | develop the program. If you encounter a problem, | ||
there should be only a small amount of new code | there should be only a small amount of new code | ||
that is not known to be correct. | that is not known to be correct. | ||
do what I expect. | <H3 CLASS="subsection">A.3.2  I’ve got a big hairy expression and it doesn’t | ||
do what I expect.</H3> | |||
Writing complex expressions is fine as long as they are readable, | |||
but they can be hard to debug. It is often a good idea to | but they can be hard to debug. It is often a good idea to | ||
break a complex expression into a series of assignments to | break a complex expression into a series of assignments to | ||
temporary variables. | temporary variables. | ||
For example: | |||
<PRE CLASS="verbatim">self.hands[i].addCard(self.hands[self.findNeighbor(i)].popCard()) | |||
</PRE> | |||
This can be rewritten as: | |||
<PRE CLASS="verbatim">neighbor = self.findNeighbor(i) | |||
pickedCard = self.hands[neighbor].popCard() | pickedCard = self.hands[neighbor].popCard() | ||
self.hands[i].addCard(pickedCard) | self.hands[i].addCard(pickedCard) | ||
</PRE> | |||
The explicit version is easier to read because the variable | |||
names provide additional documentation, and it is easier to debug | names provide additional documentation, and it is easier to debug | ||
because you can check the types of the intermediate variables | because you can check the types of the intermediate variables | ||
and display their values. | and display their values. | ||
Another problem that can occur with big expressions is | |||
that the order of evaluation may not be what you expect. | that the order of evaluation may not be what you expect. | ||
For example, if you are translating the expression | For example, if you are translating the expression | ||
<I>x</I>/2 π into Python, you might write: | |||
<PRE CLASS="verbatim">y = x / 2 * math.pi | |||
</PRE> | |||
That is not correct because multiplication and division have | |||
the same precedence and are evaluated from left to right. | the same precedence and are evaluated from left to right. | ||
So this expression computes | So this expression computes <I>x</I> π / 2. | ||
the order of evaluation explicit: | |||
A good way to debug expressions is to add parentheses to make | |||
the order of evaluation explicit: | |||
<PRE CLASS="verbatim"> y = x / (2 * math.pi) | |||
</PRE> | |||
Whenever you are not sure of the order of evaluation, use | |||
parentheses. Not only will the program be correct (in the sense | parentheses. Not only will the program be correct (in the sense | ||
of doing what you intended), it will also be more readable for | of doing what you intended), it will also be more readable for | ||
other people who haven’t memorized the rules of precedence. | other people who haven’t memorized the rules of precedence. | ||
expect. | <H3 CLASS="subsection">A.3.3  I’ve got a function or method that doesn’t return what I | ||
expect.</H3> | |||
you don’t have a chance to print the | |||
If you have a <TT>return</TT> statement with a complex expression, | |||
you don’t have a chance to print the <TT>return</TT> value before | |||
returning. Again, you can use a temporary variable. For | returning. Again, you can use a temporary variable. For | ||
example, instead of: | example, instead of: | ||
<PRE CLASS="verbatim">return self.hands[i].removeMatches() | |||
</PRE> | |||
you could write: | |||
<PRE CLASS="verbatim">count = self.hands[i].removeMatches() | |||
return count | return count | ||
</PRE> | |||
Now you have the opportunity to display the value of | |||
<TT>count</TT> before returning. | |||
==== A.3.4  I’m really, really stuck and I need help. ==== | |||
First, try getting away from the computer for a few minutes. | |||
Computers emit waves that affect the brain, causing these | Computers emit waves that affect the brain, causing these | ||
symptoms: | symptoms: | ||
*Frustration and rage. | |||
*Superstitious beliefs (“the computer hates me”) and | |||
magical thinking (“the program only works when I wear my | magical thinking (“the program only works when I wear my | ||
hat backward”). | hat backward”). | ||
*Random walk programming (the attempt to program by writing | |||
every possible program and choosing the one that does the right | every possible program and choosing the one that does the right | ||
thing). | thing). | ||
If you find yourself suffering from any of these symptoms, get | |||
up and go for a walk. When you are calm, think about the program. | up and go for a walk. When you are calm, think about the program. | ||
What is it doing? What are some possible causes of that | What is it doing? What are some possible causes of that | ||
behavior? When was the last time you had a working program, | behavior? When was the last time you had a working program, | ||
and what did you do next? | and what did you do next? | ||
Sometimes it just takes time to find a bug. I often find bugs | |||
when I am away from the computer and let my mind wander. Some | when I am away from the computer and let my mind wander. Some | ||
of the best places to find bugs are trains, showers, and in bed, | of the best places to find bugs are trains, showers, and in bed, | ||
just before you fall asleep. | just before you fall asleep. | ||
==== A.3.5  No, I really need help. ==== | |||
It happens. Even the best programmers occasionally get stuck. | |||
Sometimes you work on a program so long that you can’t see the | Sometimes you work on a program so long that you can’t see the | ||
error. A fresh pair of eyes is just the thing. | error. A fresh pair of eyes is just the thing. | ||
Before you bring someone else in, make sure you are prepared. | |||
Your program should be as simple | Your program should be as simple | ||
as possible, and you should be working on the smallest input | as possible, and you should be working on the smallest input | ||
that causes the error. You should have | that causes the error. You should have <TT>print</TT> statements in the | ||
appropriate places (and the output they produce should be | appropriate places (and the output they produce should be | ||
comprehensible). You should understand the problem well enough | comprehensible). You should understand the problem well enough | ||
to describe it concisely. | to describe it concisely. | ||
them the information they need: | |||
and what part of the program does it indicate? | When you bring someone in to help, be sure to give | ||
them the information they need: | |||
*If there is an error message, what is it | |||
and what part of the program does it indicate? | |||
*What was the last thing you did before this error occurred? | |||
What were the last lines of code that you wrote, or what is | What were the last lines of code that you wrote, or what is | ||
the new test case that fails? | the new test case that fails? | ||
*What have you tried so far, and what have you learned? | |||
When you find the bug, take a second to think about what you | |||
could have done to find it faster. Next time you see something | could have done to find it faster. Next time you see something | ||
similar, you will be able to find the bug more quickly. | similar, you will be able to find the bug more quickly. | ||
work. The goal is to learn how to make the program work. | |||
Remember, the goal is not just to make the program | |||
work. The goal is to learn how to make the program work. | |||
<HR> | |||
<IMG SRC="previous_motif.gif" ALT="Previous"> | |||
<IMG SRC="contents_motif.gif" ALT="Up"> | |||
<IMG SRC="next_motif.gif" ALT="Next"> | |||