This page intentionally left blank Python for Software Design



tải về 1.38 Mb.
Chế độ xem pdf
trang81/83
Chuyển đổi dữ liệu13.08.2023
Kích1.38 Mb.
#55046
1   ...   75   76   77   78   79   80   81   82   83
- Python for Software Design How to Think Like a Computer Scientist-Cambridge University Press (2009)

NameError: You are trying to use a variable that doesn’t exist in the current
environment. Remember that local variables are local. You cannot refer to
them from outside the function where they are defined.
TypeError: 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 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 check that the first param-
eter is self. Then look at the method invocation; make sure you are
invoking the method on an object with the right type and providing the
other arguments correctly.
KeyError: You are trying to access an element of a dictionary using a key that
the dictionary does not contain.
AttributeError: You are trying to access an attribute or method that does not
exist. Check the spelling! You can use dir to list the attributes that do exist.
If an AttributeError indicates that an object has NoneType, that means that it
is None. One common cause is forgetting to return a value from a function; if
you get to the end of a function without hitting a return statement, it returns
None
. Another common cause is using the result from a list method, like sort,
that returns None.
IndexError: The index you are using to access a list, string, or tuple is greater
than its length minus one. Immediately before the site of the error, add a print
statement to display the value of the index and the length of the array. Is the
array the right size? Is the index the right value?
The Python debugger (pdb) is useful for tracking down Exceptions because it allows
you to examine the state of the program immediately before the error. You can read
about pdb at docs.python.org/lib/module-pdb.html.
A.2.4
I Added so Many print Statements I Get Inundated with Output
One of the problems with using print statements for debugging is that you can end
up buried in output. There are two ways to proceed: simplify the output or simplify
the program.
To simplify the output, you can remove or comment out print statements that aren’t
helping, or combine them, or format 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 are searching a list, search


236
Debugging
small list. If the program takes input from the user, give it the simplest input that
causes the 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 suspect that the problem is
in a deeply nested part of the program, try rewriting that part with simpler structure.
If you suspect a large function, try splitting it into smaller functions and testing them
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 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 shouldn’t affect the 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 about what is wrong. Only you know what the program is
supposed to do.
The first step is to make a connection between the program text and the behavior
you are seeing. You need a hypothesis about what the program is actually doing.
One of the things 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 insert a few well-placed print
statements is often short compared to setting up the debugger, inserting and removing
breakpoints, and “stepping” the program to where the error is occurring.
A.3.1
My Program Does not 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 that performs that function and make
sure it is executing when you think it should.

Is something happening that shouldn’t? Find code in your program that performs
that function and see if it is 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 question, especially if it involves invocations to
functions or methods in other Python modules. Read the documentation for the
functions you invoke. 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, very often the problem is not
in the program; it’s in your mental model.


A.3 Semantic Errors
237
The best way to correct your mental model is to break the program into its compo-
nents (usually the functions and methods) and test each component independently.
Once you find the discrepancy between your model and reality, you can solve the
problem.
Of course, you should be building and testing components as you develop the pro-
gram. If you encounter a problem, there should be only a small amount of new code
that is not known to be correct.
A.3.2
I’ve Got A Big Hairy Expression and It Doesn’t Do What I Expect
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 break a complex expression into a series of
assignments to temporary variables.
For example:
self.hands[i].addCard(self.hands[self.findNeighbor(i)].popCard())
This can be rewritten as:
neighbor = self.findNeighbor(i)
pickedCard = self.hands[neighbor].popCard()
self.hands[i].addCard(pickedCard)
The explicit version is easier to read because the variable names provide additional
documentation, and it is easier to debug because you can check the types of the
intermediate variables and display their values.
Another problem that can occur with big expressions is that the order of evaluation
may not be what you expect. For example, if you are translating the expression

tải về 1.38 Mb.

Chia sẻ với bạn bè của bạn:
1   ...   75   76   77   78   79   80   81   82   83




Cơ sở dữ liệu được bảo vệ bởi bản quyền ©hocday.com 2024
được sử dụng cho việc quản lý

    Quê hương