What's the best way to minimize the need of run time checks?
Steven D'Aprano
steve+comp.lang.python at pearwood.info
Wed Aug 10 02:47:15 EDT 2016
On Wednesday 10 August 2016 15:20, Juan Pablo Romero Méndez wrote:
> Ok, so you suggested 1) catching exceptions at the point where you care, 2)
> preemptively check for certain runtime conditions to avoid exceptions 3)
> write as many tests as possible 4) learn to live with runtime errors.
>
> Is that a fair characterization?
(1) Not quite.
Only catch exceptions you expect and *can deal with*. By deal with, I mean
either recover from, or convert to a user-friendly error message (perhaps
displaying it in a dialog for GUI apps).
Your script or application may want to use a top-level exception handler to
catch any *unexpected* exceptions, log them, perform any extra cleanup needed,
and display a nice error message before exiting. But that counts as gold-
plating: for many applications or scripts, aimed at technical or semi-technical
users, its acceptable to just let the traceback print and the interpreter exit.
(2) Sometimes. Its a judgement call whether it is better to "Look Before You
Leap" or "Easier To Ask For Forgiveness Rather Than Permission". It depends on
what you are doing, how often you expect an exceptional case, the performance
implications, whether there is a risk of "Time Of Check To Time Of Use" bug,
etc. In other words, that's usually a technical question, not a matter of
style.
Google for LBYL versus EAFP for more discussion.
Occasionally it comes down to both being equally good, in which case you get to
pick whichever you like.
(3) Yes, this is correct.
Basically, with a dynamically-typed language like Python, you have to write all
the tests you would write with a statically-typed language, plus some more.
There's no question that the cost of the freedom dynamic typing gives you is
that you have to write extra tests. But not as many as you might think.
The major differences in mindset between dynamic/static typing are:
- Where the compiler would detect a type error at compile time, you get the
same result with a small unit test that checks for TypeError or AttributeError
instead.
(Although see also the MyPy project, which brings an optional static type-
checker to Python.)
- As much as possible, avoid thinking "I need a list", and instead think "I
need anything which offers the list interface". (Duck-typing.)
That *especially* counts for writing library code, application code you can be
a bit more strict about types because you're only limiting yourself, not other
users.
- A Python runtime exception is not like a segmentation fault. Its not going to
overflow a buffer and execute random code. It's a controlled failure, not an
uncontrolled one.
(4) There's no necessary reason to expect that you'll get more runtime errors
in a well-written and tested Python application than you get in a well-written
and tested C application.
Regardless of the language, you have to deal with runtime errors:
- network is down;
- disk is full;
- user lacks permission to edit that file;
- database error;
- account not found;
etc. Python is no different. And regardless of the language, the compiler can't
check that "add_account" actually adds the account, you need a unit-test to
check that. So you have to write tests either way.
Basically, just relax -- static type checks aren't useless, but they do very
little that a runtime exception won't give you. So long as you have a good
suite of unit tests that exercises the whole program, you'll find your type
errors when they raise TypeError, then you fix them.
You may be gathering from this that dynamic typing and Test Driven Development
go hand in hand. That's exactly right. They complement each other very well.
--
Steve
More information about the Python-list
mailing list