if or exception

T

Thomas Lindgaard

Hi

Just wondering what is "the right thing to do":

number = 0
if len(list) > 0: number = anotherNumber / len(list)

or

try:
number = anotherNumber / len(list)
except:
number = 0
 
D

Duncan Booth

Hi

Just wondering what is "the right thing to do":

number = 0
if len(list) > 0: number = anotherNumber / len(list)

or

try:
number = anotherNumber / len(list)
except:
number = 0

Your first suggestion may be the right answer in some situations.

Your second suggestion is never the right answer. This on the other, could
be a suitable answer:

try:
number = anotherNumber / len(aList)
except ZeroDivisionError:
number = 0

Don't use a bare except, it will just mask other errors: if you feel that
catching an exception is the way to go, then catch only the exceptions that
you expect. Also, but minor, don't use 'list' as a variable name.

However, it seems to me that I would be unlikely to use either of these. I
can't think of a situation where I would want a value that is either the
result of a division, or 0 if the division failed. It is much more likely
that you want to execute some different code if the list is empty than that
you want a different value.

If you explained what problem you are solving leads to this code then you
might get a more useful suggestion about style.
 
T

Thomas Lindgaard

[snip]
Your first suggestion may be the right answer in some situations.

Your second suggestion is never the right answer. This on the other, could
be a suitable answer:

try:
number = anotherNumber / len(aList)
except ZeroDivisionError:
number = 0

Hmm... somehow that ZeroDivisionError got lost in translation... is
_was_ supposed to be there :)
Don't use a bare except, it will just mask other errors: if you feel
that catching an exception is the way to go, then catch only the
exceptions that you expect. Also, but minor, don't use 'list' as a
variable name.

I only used 'list' as a variable name to illustrate the type.
However, it seems to me that I would be unlikely to use either of these.
I can't think of a situation where I would want a value that is either
the result of a division, or 0 if the division failed. It is much more
likely that you want to execute some different code if the list is empty
than that you want a different value.

If you explained what problem you are solving leads to this code then
you might get a more useful suggestion about style.

The situation is this: I am trying to make my web crawler "spread out",
ie. I want it to fetch an equal number of pages from each known host (and
not 8000 pages from one host and 1 page from another host as it does now).
Setting number = 0 on ZeroDivisionError was just the first result that
came to mind... after writing the the pseudo code below I can see that it
should have been something along the lines of number = 42 in stead :)

+--- pseudo code ---
| # hostDict is a dictionary mapping currently known host names to info
| # about the host (ie. time for last visit and number of pages fetched
| # from the host)
|
| class Crawler:
| ...
|
| def startPages(self):
| try:
| avgPagesPerHost = numPagesFetched / len(hostDict)
| except ZeroDivisionError:
| # this will only happen the first time around when no hosts are
| # known
| avgPagesPerHost = 42
|
| while len(queue):
| link = queue.pop()
| host = parseLinkAndExtractHost(link)
|
| # a lot of checks
|
| if hostDict[host]['numPagesFetchedFromHost'] < avgPagesPerHost:
| fetchPage(link)
| else:
| delayPage(link)
+----

If the average number of pages found on a host turns out to be 10, then
something has to be done to make sure that the crawler continues fetching
pages from hosts with more than 10 pages... but that is another problem
entirely :)
 
C

Christopher T King

Just wondering what is "the right thing to do":

number = 0
if len(list) > 0: number = anotherNumber / len(list)

or

try:
number = anotherNumber / len(list)
except:
number = 0

The first will be faster if you expect len(list) to be zero very often,
whereas the latter will be faster if you expect it to be zero very rarely.

This is because in the normal case, the latter needs no extra code (except
a quick 'setup try block'), whereas the former requires a function call
and a comparison for all cases. In the exceptional case, the latter must
raise an catch an exception, which (I believe) is more expensive than the
check in the former. How much more expensive, I'm not qualified to say ;)
 
M

Matteo Dell'Amico

Thomas Lindgaard wrote:

[...]
| def startPages(self):
| try:
| avgPagesPerHost = numPagesFetched / len(hostDict)
| except ZeroDivisionError:
| # this will only happen the first time around when no hosts are
| # known
| avgPagesPerHost = 42

[...]

I'd do it the way you have done, but I wouldn't call it
'avgPagesPerHost', since it's a bit misleading, but something along the
lines of 'perHostLimit'.

I'd write the if/else version as:

if numPagesFetched != 0:
perHostLimit = ...
else:
perHostLimit = 42

But since here the standard case seems to be the first one, I think a
try/except solution is both clearer and more efficient.
 
S

Steve

Duncan said:
However, it seems to me that I would be unlikely to use either of these. I
can't think of a situation where I would want a value that is either the
result of a division, or 0 if the division failed.

What about code for cos(x)/x? By l'Hôpital's Rule, the
limit as x->0 is 0.

Admittedly practical applications for cos(x)/x aren't
as common as for sin(x)/x. Perhaps evaluating the
derivative of sinc(x) is a better example.

Or one might want code to handle a continued fraction
of the form [1; 2, 1, 0] which should evaluate as 1.5
except for the pesky divide-by-zero error.

The moral of the story: even if you can't think of an
application for something, somebody else might.
> It is much more likely
that you want to execute some different code if the list is empty than that
you want a different value.

But the question still remains: is it better to do this:

if myList:
call_standard_code(myList)
else:
call_exceptional_code(myList)

or this:

try:
call_standard_code(myList)
except SomeSortOfExceptionHere:
call_exceptional_code(myList)


The essential question remains: is it better to test
for exceptional cases first or just try it and catch
the exception when it happens?

And the answer is, "It depends."

Apart from issues of aesthetics, it also depends on how
often you expect exceptions to occur, and how much work
is needed to determine whether an error will occur
before hand. If it is easy to check for errors up
front, I'd probably stick with the if form. If it takes
just as much work to determine the existance of the
error condition as it takes to actually perform your
calculation, stick to using the try...except form.

But the only way to know for sure which is quicker is
to write both versions and time them with realistic data.
 
C

Christopher T King

What about code for cos(x)/x? By l'Hôpital's Rule, the
limit as x->0 is 0.

Not to be nitpicky, but isn't l'Hôpital only valid in the case that
lim{x->0+} f(x) = lim{x->0-} f(x); i.e. the function approaches the same
value from the left and from the right? cos(x)/x approaches infinity from
the right, but negative infinity from the left, so I think that means it's
undefined at zero. Feel free to correct me though, it's been a couple of
years since Calc III ;)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,202
Messages
2,571,057
Members
47,665
Latest member
salkete

Latest Threads

Top