What is the point of using an else clause if there is a return instruction in the except clause?
def foo():
try:
# Some code
except:
# Some code
return
else:
# Some code
I'm asking this question because the Django documentation does it at some point, in the vote() function. Considering that the return instruction in the except clause will anyway stop the execution of the function, why did they use an else clause to isolate the code that should only be executed if no exception was raised? They could have just omitted the else clause entirely.
If there is no exception in the try: suite, then the else: suite is executed. In other words, only if there is an actual exception is the except: suite reached and the return statement used.
In my view, the return statement is what is redundant here; a pass would have sufficed. I'd use an else: suite to a try when there is additional code that should only be executed if no exception is raised, but could raise exceptions itself that should not be caught.
You are right that a return in the except clause makes using an else: for that section of code somewhat redundant. The whole suite could be de-dented and the else: line removed:
def foo():
try:
# Some code
except:
# Some code
return
# Some code
From the docs:
The use of the else clause is better than adding additional code to the try clause because it avoids accidentally catching an exception that wasn’t raised by the code being protected by the try ... except statement.
http://docs.python.org/2/tutorial/errors.html#handling-exceptions
Related
Both these snippets do the same thing:
Try/except in function declaration:
def something():
try:
# code goes here
except:
print("Error")
sys.exit(1)
something()
Try/except in function call:
def something():
# code goes here
try:
something()
except:
print("Error")
sys.exit(1)
Is there one that is better/more Pythonic/recommended by PEP8 or is it just up to personal preference? I understand that the second method would get tedious and repetitive if the function needs to be called more than once, but assuming the function is only called once, which one should I use?
the general rule is "only catch exceptions you can handle", see here for an explanation
note that an uncaught exception (in most languages) will cause the program to exit with an unsuccessful status code (i.e. your sys.exit(1)), it will probably also print out a message saying that an exception occurred. your demo therefore is emulating default behaviour, but doing it worse
further, you're catching every exception and this is generally bad style, e.g. you'll implicitly catch SystemExit and other internal exceptions that you probably shouldn't be dealing interacting with
I have this rather intricate try except block:
try:
self.sorting = sys.argv[1]
try:
test_sorting_var = int(self.sorting)
if test_sorting_var < 1:
print "Sorting column number not valid."
raise ValueError
else:
self.sorting = test_sorting_var
except ValueError:
print "There's a problem with the sorting value provided"
print "Either the column doesn't exists or the column number is invalid"
print "Please try a different sorting value or omit it."
sys.exit(1)
except:
if self.sorting not in self.output_table.column_headers:
print "Sorting column name not valid."
raise ValueError
except:
pass
Basically I'm checking:
If there's a sys.argv[1]
If so, try it as int, and see if it's less than 1
If int fails, test it as string
In both 2+3, if the tests don't succeed, I'm raising a ValueError that should be caught in the except ValueError block and it does as expected:
Sorting column number not valid.
There's a problem with the sorting value provided
Either the column doesn't exists or the column number is invalid
Please try a different sorting value or omit it.
BUT! The sys.exit(1) is not invoked and the program just continues.
How can I fix it and even make it more readable?
In the last two lines you catch any exception:
except:
pass
This includes the exception SystemExit, which is raised by sys.exit.
To fix this, only catch exceptions deriving from Exception, which
SystemExit does not:
except Exception:
pass
In general, it's (almost) never a good idea to do a bare except, always catch Exception, or if possible, something more specific.
The builtint sys.exit() raises a SystemExit-Exception. As you are catching any type of exception when you don't define the Exception to catch (except: without an Exception Type) the SystemExit gets also caught. Ultimately the function will run until the last line where you wrote pass.
Best thing to do is to always catch specific Exceptions and never ever catch all Exceptions with an except:.
Furthermore you should put the check if self.sorting is not in self.output_table.column_headers outside the try catch where you check for a valid self.sorting.
From the documentation for sys.exit:
Exit from Python. This is implemented by raising the SystemExit exception, so cleanup actions specified by finally clauses of try statements are honored, and it is possible to intercept the exit attempt at an outer level.
This means that the outer try except loop is catching the SystemExit exception and causing it to pass. You can add this exception to the outer block and call it again.
I think I would do something like this:
import sys
def MyClass(object):
def method(self, argv, ...):
# ...
if len(argv) < 2:
raise RuntimeError("Usage: {} <sorting column>".format(argv[0]))
sorting = argv[1]
try:
self.sorting = int(sorting)
except ValueError:
try:
self.sorting = self.output_table.column_headers.index(sorting)
except ValueError:
raise ValueError("Invalid sorting column '{}'.".format(sorting))
# ...
try:
# ...
obj.method(sys.argv, ...)
except Exception as e:
sys.exit(e.message)
It's okay to ask for forgiveness instead of permission when it makes things easier (for example to parse a number), but if you need to make sure if sys.argv has enough elements just check it, it will make the program flow clearer.
Avoid using sys.exit within regular code, try to use it only in the outermost levels. For the most part, it is generally better to let exceptions bubble up and catch them at top level or let them crash the program if necessary.
Do make use of exception parameters to store error information, you can decide at a later point whether to print the error, log it, show it in a popup, ...
Instead of using sys.argv directly from within a class, you can pass it as an argument to the method/constructor, it will make the code easier to test and more flexible towards the future.
Is it pythonic to call one function after the other? I have two functions, and one depends of the result of the other:
function1() # if something goes wrong, will raise a error, if not, will return None
function2()
And I was thinking about using:
function1() is None and function2()
Is this pythonic?
You shouldn't think of the return value of None as indicating success, but rather the absence of an exception. Use a try statement to make it explicit that you are aware of the possibility of an exception, but are intentionally letting it pass up the call chain should one be raised:
try:
function1()
else:
function2()
If you want, you can be explicit:
try:
function1()
except Exception:
raise
else:
function2()
I would be tempted to use a try....except test instead of two separate functions
MyFunction()
try:
<your first action goes here>
except:
<what you want to happen if an error occurs go here>
You might need to use two except statements, one for a None return and one for any others. There is plenty of useful information in the documentation: https://wiki.python.org/moin/HandlingExceptions
I have a code for a function which is called inside another function.(Result of refactoring).
So in the called function I have a huge block of try-catch statements as.
def Called():
try:
#All statements for the function in the try block.
except A:
# Exception handler.
except B:
# Exception handler.
except A:
# Exception handler.
The problem I have is that I need to catch two exceptions of the same type (At different locations in the Called function). Which then are handled by the Calling function.
One way would be to define two try-except blocks within the Called function. But I am not understanding how the Calling function can handle two exceptions of the same type differently.
This won't work as advertised; only the first except A clause will ever get executed. What you need is either some logic inside the clause to further inspect the exception, or (if the code inside the try block permits) several try-except blocks.
Example of the former approach:
try:
something_that_might_fail()
except A as e:
if e.is_harmless():
pass
elif e.is_something_we_can_handle():
handle_it()
else:
raise # re-raise in the hope it gets handled further up the stack
I think this will work
def Called():
try:
#All statements for the function in the try block.
except A:
try:
do_someting()
except B:
try:
do_somthing_else()
except:
except A:
# Exception handler.
Is there a way to prevent StopIteration exceptions from being thrown from unrelated code (without having to catch them manually)?
Example: loop_all wants to loop through the myiter iterator and simply move on when this one has finished. This works unless some_dangerous_method or any other code in myiter raises a StopIteration.
def loop_all():
myiter = myiter()
try:
while True:
next(myiter) # <- I want exactly the StopIteration from this next method
except StopIteration:
pass
def myiter():
some_dangerous_method() # what if this also raises a StopIteration?
for i in some_other_iter():
# here may be more code
yield
Is there a way to make it clear to which StopIteration the code should react to?
If a function you are calling is invoking next(iter), and isn't dealing with StopIteration, then that function has a bug. Fix it.
Perhaps I'm missing something but why not simply this:
def myiter():
try:
some_dangerous_method()
except StopIteration:
pass # or raise a different exception
for i in some_other_iter():
# here may be more code
yield