When using try/except blocks in Python, is there a recommendation to delegate it to any methods that might raise an exception, or to catch it in the parent function, or both?
For example, which of the following is preferred?
def my_function():
s = something.that.might.go_wrong()
return s
def main():
try:
s = my_function()
except Exception:
print "Error"
or
def my_function():
try:
s = something.that.might.go_wrong()
return s
except Exception:
print "Error"
def main():
s = my_function()
PEP 8 seems to be quiet on the matter, and I seem to find examples of both cases everywhere.
It really depends on the semantics of the functions in question. In general if you're writing a library, your library probably should handle exceptions that get raised inside the library (optionally re-raising them as new library-specific exceptions).
At the individual function level, though, the main thing you want to think about is what context/scope you desire to handle the exception in - if there is a reasonable different thing you could do in exceptional cases within the inner function, it might be useful to handle it within the inner function; otherwise, it might make more sense to handle it in the outer function.
For the specific case of writing output, it's often useful to only do that at the highest level, and inner functions only ever (a) return values or (b) raise exceptions. That makes the code easier to test because you don't have to worry about testing side effect output.
If you are following the rule of "one function should handle one task" then You shouldn't handle exception in that function, Let it fail loudly on unexpected input. Parent function which calling such function may handle to give better experience to user.
We can refer python builtin functions to get pythonic way
I always use the second one. Logically to me it seems that the problems of a function should be dealt with in that function only. This would provide user a clean and a hassle free interface, so you could later put your code in a library.
There could be some cases where you would want to use exceptions outside the function. For example if you want to print a particular message when something goes wrong then you should use the exception out of the function.
However you could provide the exception statements as a argument to the function if you want to give user the ability to decide his own exception message. So i guess the Second example(exception inside the function) would be universal and thus should be preferred.
Related
I've method or function like:
findSomething(v)
Is appropriate to raise KeyError in the case I don't find anything or it's better to define my own exception? What do you think?
I know, it isn't strictly technical question, but they said: 'Readability counts' and I need to know what others think. :)
If the nature of the Error is complex, and its use also repeats in other places in your code I would define a custom Error.
Just cause it's more readable to write:
raise MyError('reason for MyError')
Than:
raise ValueError('the is an Error of type MyError, and here is the reason...')
But if it's not a repeatable part of your code, and the error is clear, I would use ValueError (before KeyError).
Might be closed as opinion-based, but.
I prefer to limit KeyError, ValueError etc to local scope, i.e no bigger than inside 1 function, preferably logical block inside.
Let's say you've caught a KeyError a couple layers from the original place the exception has taken place.
It gives you basically no information and could have happened basically anywhere.
A function calling another one shouldn't know about implementation details of the callee.
Also you're not writing a code to check exception stack trace and use it in your code logic, are you ?
Defining custom exception gives you the opportunity to describe location and high-level explanation of an issue like UserNotFound or NoMatchingChannel.
The code where you will catch it will give more insight about what is the issue and how to deal with it.
Well, I guess readability is more related to how you code, say how you name variables, functions, etc., how you structure your code and comment it.
But, regarding the exception handling question that you have: these are the things I think you should consider:
1- If the function gets a valid input and does not find anything you shouldn't throw or define an exception. You just need to return a value that represents you didn't find anything and/or just print a proper message.
2- If the input parameter, v, is invalid depending whether it is an object instantiated from a class or just a primitive type, you could define a proper exception for it or just catch a built-in exception, respectively.
Is it pythonic to store the expected exceptions of a funcion as attributes of the function itself? or just a stinking bad practice.
Something like this
class MyCoolError(Exception):
pass
def function(*args):
"""
:raises: MyCoolError
"""
# do something here
if some_condition:
raise MyCoolError
function.MyCoolError = MyCoolError
And there in other module
try:
function(...)
except function.MyCoolError:
#...
Pro: Anywhere I have a reference to my function, I have also a reference to the exception it can raise, and I don't have to import it explicitly.
Con: I "have" to repeat the name of the exception to bind it to the function. This could be done with a decorator, but it is also added complexity.
EDIT
Why I am doing this is because I append some methods in an irregular way to some classes, where I think that a mixin it is not worth it. Let's call it "tailored added functionality". For instance let's say:
Class A uses method fn1 and fn2
Class B uses method fn2 and fn3
Class C uses fn4 ...
And like this for about 15 classes.
So when I call obj_a.fn2(), I have to import explicitly the exception it may raise (and it is not in the module where classes A, B or C, but in another one where the shared methods live)... which I think it is a little bit annoying. Appart from that, the standard style in the project I'm working in forces to write one import per line, so it gets pretty verbose.
In some code I have seen exceptions stored as class attributes, and I have found it pretty useful, like:
try:
obj.fn()
except obj.MyCoolError:
....
I think it is not Pythonic. I also think that it does not provide a lot of advantage over the standard way which should be to just import the exception along with the function.
There is a reason (besides helping the interpreter) why Python programs use import statements to state where their code comes from; it helps finding the code of the facilities (e. g. your exception in this case) you are using.
The whole idea has the smell of the declaration of exceptions as it is possible in C++ and partly mandatory in Java. There are discussions amongst the language lawyers whether this is a good idea or a bad one, and in the Python world the designers decided against it, so it is not Pythonic.
It also raises a whole bunch of further questions. What happens if your function A is using another function B which then, later, is changed so that it can throw an exception (a valid thing in Python). Are you willing to change your function A then to reflect that (or catch it in A)? Where would you want to draw the line — is using int(text) to convert a string to int reason enough to "declare" that a ValueError can be thrown?
All in all I think it is not Pythonic, no.
Is there a way to 'detect' what exceptions function/method raises? Examplifying:
def foo():
print 'inside foo, next calling bar()'
_bar()
_baz()
# lots of other methods calls which raise other legitimate exceptions
def _bar():
raise my_exceptions.NotFound
def _baz():
raise my_exceptions.BadRequest
so, supposing that foo is part of my API and I need to document it, is there a way to get all exceptions that can be raised from it?
Just to be clear I don't want to handle those exceptions, they are supposed to happen (when a resource is not found or the request is malformed for instance).
I'm thinking to create some tool that transform that sequence of code in something 'inline' like:
def foo():
print 'inside foo, next calling bar()'
# what _bar() does
raise my_exceptions.NotFound
# what _baz() does
raise my_exceptions.BadRequest
# lots of other methods calls which raise other legitimate exceptions
Is there anything that can help me detect that instead of navigate through each method call? (Which goes deep into several files.)
You can't reasonably do this with Python, for a few reasons:
1) The Python primitives don't document precisely what exceptions they can throw. The Python ethos is that anything can throw any exception at any time.
2) Python's dynamic nature makes it very difficult to statically analyze code at all, it's pretty much impossible to know what code "might" do.
3) All sorts of uninteresting exceptions would have to be in the list, for example, if you have self.foo, then it could raise AttributeError. It would take a very sophisticated analyzer to figure out that foo must exist.
No, because of the dynamic nature of Python. How would your tool work if a function took another function chosen at runtime (very common), or if the code is later monkeypatched?
There's simply no way to know ahead of time (in enough situations for it to be useful), what the interpreter is going to do through static analysis. You effectively have to run the interpreter and see what happens, which of course could change between runs...
There is a list standard python exceptions that we should watch out, but I don't think these are the ones we should raise ourselves, cause they are rarely applicable.
I'm curious if there exists a list within standard python library, with exceptions similar to .NET's ApplicationException, ArgumentNullException, ArgumentOutOfRangeException, InvalidOperationException — exceptions that we can raise ourselves?
Or is there different, more pythonic way to handle common error cases, than raising standard exceptions?
EDIT: I'm not asking on how to handle exceptions but what types I can and should raise where needed.
If the error matches the description of one of the standard python exception classes, then by all means throw it.
Common ones to use are TypeError and ValueError, the list you linked to already is the standard list.
If you want to have application specific ones, then subclassing Exception or one of it's descendants is the way to go.
To reference the examples you gave from .NET
ApplicationException is closest to RuntimeError
ArgumentNullException will probably be an AttributeError (try and call the method you want, let python raise the exception a la duck typing)
AttributeOutOfRange is just a more specific ValueError
InvalidOperationException could be any number of roughly equivalent exceptions form the python standard lib.
Basically, pick one that reflects whatever error it is you're raising based on the descriptions from the http://docs.python.org/library/exceptions.html page.
First, Python raises standard exceptions for you.
It's better to ask forgiveness than to ask permission
Simply attempt the operation and let Python raise the exception. Don't bracket everything with if would_not_work(): raise Exception. Never worth writing. Python already does this in all cases.
If you think you need to raise a standard exception, you're probably writing too much code.
You may have to raise ValueError.
def someFunction( arg1 ):
if arg1 <= 0.0:
raise ValueError( "Guess Again." )
Once in a while, you might need to raise a TypeError, but it's rare.
def someFunctionWithConstraints( arg1 ):
if isinstance(arg1,float):
raise TypeError( "Can't work with float and can't convert to int, either" )
etc.
Second, you almost always want to create your own, unique exceptions.
class MyException( Exception ):
pass
That's all it takes to create something distinctive and unique to your application.
I seem to recall being trained by the documentation that it is ok to raise predefined exceptions, as long as they are appropriate. For example, the recommended way to terminate is no longer to call exit() but rather to raise SystemExit.
Another example given is to reuse the IndexError exception on custom container types.
Of course, your application should define its own exceptions rather than to actually repurpose system exceptions. I'm just saying there's no prohibition from reusing them where appropriate.
The Pythonic way is just let the exceptions pass through from Python itself. For example, instead of:
def foo(arg):
if arg is None:
raise SomeNoneException
bar = arg.param
Just do:
def foo(arg):
bar = arg.param
If arg is None or doesn't have the param attribute, you will get an exception from Python itself.
In the Python glossary this is called "EAFP":
Easier to ask for forgiveness than permission. This common Python coding
style assumes the existence of valid
keys or attributes and catches
exceptions if the assumption proves
false. This clean and fast style is
characterized by the presence of many
try and except statements. The
technique contrasts with the LBYL (Look Before You Leap)
style common to many other languages
such as C.
And it works well in tandem with Python's inherent duck typing philosophy.
This doesn't mean you should not create exceptions of your own, of course, just that you don't need to wrap the already existing Python exceptions.
For your own exceptions, create classes deriving from Exception and throw them when it's suitable.
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 ?
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.
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.
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.