views:

142

answers:

3

My work place has imposed a rules for no use of exception (catching is allowed). If I have code like this

def f1()
 if bad_thing_happen():
   raise Exception('bad stuff')
 ...
 return something

I could change it to

def f1()
  if bad_thing_happen():
    return [-1, None]
  ...
  return [0, something]

f1 caller would be like this

def f1_caller():
  code, result = f1(param1)
  if code < 0:
    return code
  actual_work1()
  # call f1 again
  code, result = f1(param2)
  if code < 0:
    return code
  actual_work2()
  ...

Are there more elegant ways than this in Python ?

+2  A: 

Exceptions in python are not something to be avoided, and are often a straightforward way to solve problems. Additionally, an exception carries a great deal of information with it that can help quickly locate (via stack trace) and identify problems (via exception class or message).

Whoever has come up with this blanket policy was surely thinking of another language (perhaps C++?) where throwing exceptions is a more expensive operation (and will reduce performance if your code is executing on a 20 year old computer).

To answer your question: the alternative is to return an error code. This means that you are mixing function results with error handling, which raises (ha!) it's own problems. However, returning None is often a perfectly reasonable way to indicate function failure.

Seth
When this type of policy is implemented it's usually due to some phantom fears. Some "senior" dev at some time got bit by something and is now afraid of it and forcing the unreasonable fear.
Paul Sasik
+1  A: 

Returning None is reasonably common and works well conceptually. If you are expecting a return value, and you get none, that is a good indication that something went wrong.

Another possible approach, if you are expecting to return a list (or dictionary, etc.) is to return an empty list or dict. This can easily be tested for using if, because an empty container evaluates to False in Python, and if you are going to iterate over it, you may not even need to check for it (depending on what you want to do if the function fails).

Of course, these approaches don't tell you why the function failed. So you could return an exception instance, such as return ValueError("invalid index"). Then you can test for particular exceptions (or Exceptions in general) using isinstance() and print them to get decent error messages. (Or you could provide a helper function that tests a return code to see if it's derived from Exception.) You can still create your own Exception subclasses; you would simply be returning them rather than raising them.

Finally, I would work toward getting this ridiculous policy changed, as exceptions are an important part of how Python works, have low overhead, and will be expected by anyone using your functions.

kindall
+1  A: 

You have to use return codes. Other alternatives would involve mutable global state (think C's errno) or passing in a mutable object (such as a list), but you almost always want to avoid both in Python. Perhaps you could try explaining to them how exceptions let you write better post-conditions instead of adding complication to return values, but are otherwise equivalent.

Roger Pate