I have a complex set of conditions, from which I would like to exit once one is met.
For that I would like to use a try: / except: structure around them to exit at the right time, which is similar to a goto. A convoluted example (using a raise to break from a while) would be:
class Minor(Exception):
pass
class Major(Exception):
pass
age = 15
while True:
try:
if age > 18:
raise Major
else:
raise Minor
except Major:
print('major')
break
except Minor:
print('minor')
break
Is such use of exceptions pythonic? In other words: were exceptions intended to only catch what would have been a Traceback otherwise, or are do they have a general use like above?
EDIT: following comments, I would like to clarify that I am not looking at how to simplify this specific piece of code -- the real code is much more complex with nested loops and conditions. The part I was interested in is whether there are reasons to specifically discourage the use of exceptions.
No, this is not a pythonic approach. The usual method of flow control used to escape from nested loops immediately is to put the logic into a function and use a return statement.
PEP 3136 was once proposed as a way to escape from nested loops using labeled break and continue statements:
Labeled break and continue can improve the readability and flexibility of complex code which uses nested loops.
This PEP was rejected for Python 3.1. Guido wrote:
I'm rejecting it on the basis that code so complicated to
require this feature is very rare. In most cases there are existing
work-arounds that produce clean code, for example using 'return'.
Related
I am working on a personal API project that involves accepting requests with keywords many of which are required. Because of this I find myself writing defensively with a lot of code that looks like this:
def post(self, urlSafeKey=None):
if urlSafeKey:
# do a bunch
# of stuff
# here
else:
self.abort(400, detail="A key parameter is required")
I've been told to prefer if - else over testing negatives with if not for readability but when I go through and change all these blocks to something like this…
def post(self, urlSafeKey=None):
if not urlSafeKey: self.abort(400, detail="A key parameter is required")
# do a bunch
# of stuff
# here
…it looks cleaner and shorter, but I worry that it's an annoying stylistic habit and in the end might be less clear.
Is there a consensus on this in the Python world?
Assuming self.abort raises an exception (and thus terminates function post), I do believe it's best to avoid nesting the normal-case code inside an if. import this at an interactive interpreter prompt to be reminded of the "Zen of Python", one of whose koans is "flat is better than nested":-).
As for the one-liner
if not urlSafeKey: self.abort(400, detail="A key parameter is required")
it's a bit long for my personal tastes -- I prefer if-based one liners to be limited to very short and concise cases, such as if cond: return, if cond: continue, if cond: break, and otherwise use two lines. But this is really a minor (purely lexical!) issue compared with preferring the avoidance of nesting (i.e, check for "I'm done" conditions and exit the function or loop as early as you know it's done), which is a Python-Zen-level issue!-)
In general, following the best practice is best practice. I don't recommend oneline statements. But I see nothing wrong with testing for not urlSafeKey.
def post(self, urlSafeKey=None):
if not urlSafeKey:
self.abort(400, detail="A key parameter is required")
# do a bunch
# of stuff
# here
What's the design thinking behind this?
To me it's easier to do something like
if string.index(substring) > -1:
# do stuff
than trying to catch an exception. If the substring is not found, at least your program doesn't break.
Someone told me 'returning -1 is a bad pattern'. Why is that?
What is the Pythonic way for checking substring?
str.index() throws an exception; you were perhaps thinking of the str.find() method instead:
if string.find(substring) > -1:
The str.index() documentation explicitly states this:
Like find(), but raise ValueError when the substring is not found.
However, the correct way to test for substring membership is to use in:
if substring in string:
Because this way at least the return type of the function is fixed. Also your example is not pythonic, it should read:
if str in string:
# do stuff
Python operates under the principle of "easier to ask for forgiveness than permission" (EAFP), as explained in an answer by Sven Marnach. It allows the code for the common path to be kept together, making the logic easier to understand without inline error handling cluttering the flow. And in a program that uses import threading for non-blocking I/O, reading the variable only once makes time-of-check-to-time-of-use (TOCTTOU) bugs less likely than in look-before-you-leap style that some other languages encourage.
The major drawback of EAFP is that Python's syntax for exception handling doesn't mesh well with functional programming style. You can't catch exceptions for individual elements in the iterable input to a generator expression without defining and naming a function.
Based on PEP8 documentation, I was not able to find any reference regarding if I should use pass for aesthetic reasons on code. Based on the example below, should I keep those else or can I erase them? Until now, the main reason I'm keeping it is based on the mantra "Explicit is better than implicit."
if fields:
for i in foo:
if i == 'something':
print "something"
else:
pass
else:
pass
Yes, you can/should remove them because they do nothing.
The Python community teaches "explicit is better than implicit" as long as the explicit code does something useful. Those else: pass's however contribute nothing positive to the code. Instead, all they do is pointlessly consume two lines each.
You can safely remove those as there's no point in keeping code around that serves no purpose:
if fields:
for i in foo:
if i == 'something':
print "something"
An else pass is dead code, you should remove it, as it adds unnecessary noise to the code and anyway the code will be clearer and easier to understand without it.
I can think of few cases where pass may be useful - the latter two are temporarily stubs:
When you want to do ignore an acceptable exception
When you need to insert a breakpoint at the end of function when debugging.
As a filler in a function whose implementation you want to postpone
I cannot imagine any other case where I will use pass
EDIT:
In some cases, when implementing if-elif-else chain, and you have some common condition that requires no action - along with rare conditions that do require specific actions - for the sake of execution efficiency, you may use pass after the first if:
if <some common condition>:
pass
elif <rare condition>:
<do something>
elif <another rare condition>:
<do something else>
else:
<do another stuff>
The thing about else is that they are not just a part of the if statements; it appears in try statements and for loops too. You don't see else being used (in this context) in those areas, do you?
try:
raw_input("say my name")
except:
print "Heisenberg"
# Meh, this is not needed.
else:
pass
If we are looping over something and checking for some condition (with the if), then an else would add unnecessary lines.
Here's a loop for finding a folder:
for path in pathlist
if os.path.isdir(path):
print "Found a folder, yay!"
break
else:
continue
Clearly, else is executed in every loop and is pointless. This could be avoided as implied in the PEP 8 itself:
But most importantly: know when to be inconsistent -- sometimes the style guide just doesn't apply. When in doubt, use your best judgment.
Look at other examples and decide what looks best. And don't hesitate
to ask! When applying the guideline would make the code less readable, even for someone who is used to reading code that follows this PEP.
[Edit] changed return 0 to return. Side effects of beinga Python n00b. :)
I'm defining a function, where i'm doing some 20 lines of processing. Before processing, i need to check if a certain condition is met. If so, then I should bypass all processing. I have defined the function this way.
def test_funciton(self,inputs):
if inputs == 0:
<Display Message box>
return
<20 line logic here>
Note that the 20 line logic does not return any value, and i'm not using the 0 returned in the first 'if'.
I want to know if this is better than using the below type of code (in terms of performance, or readability, or for any other matter), because the above method looks good to me as it is one indentation less:
def test_function(self,inputs):
if inputs == 0:
<Display Message box>
else:
<20 line logic here>
In general, it improves code readability to handle failure conditions as early as possible. Then the meat of your code doesn't have to worry about these, and the reader of your code doesn't have to consider them any more. In many cases you'd be raising exceptions, but if you really want to do nothing, I don't see that as a major problem even if you generally hew to the "single exit point" style.
But why return 0 instead of just return, since you're not using the value?
First, you can use return without anything after, you don't have to force a return 0.
For the performance way, this question seems to prove you won't notice any difference (except if you're realy unlucky ;) )
In this context, I think it's important to know why inputs can't be zero? Typically, I think the way most programs will handle this is to raise an exception if a bad value is passed. Then the exception can be handled (or not) in the calling routine.
You'll often see it written "Better to ask forgiveness" as opposed to "Look before you leap". Of course, If you're often passing 0 into the function, then the try / except clause could get expensive (try is cheap, except is not).
If you're set on "looking before you leap", I would probably use the first form to keep indentation down.
I doubt the performance is going to be significantly different in either case. Like you I would tend to lean more toward the first method for readability.
In addition to the smaller indentation(which doesn't really matter much IMO), it precludes the necessity to read further for when your inputs == 0:
In the second method one might assume that there is additional processing after the if/else statement, whereas the first one makes it obvious that the method is complete upon that condition.
It really just comes down to personal preference though, you will see both methods used in practice.
Your second example will return after it displays the message box in this case.
I prefer to "return early" as in my opinion it leads to better readability. But then again, most of my returns that happen prior to the actual end of the function tend to be more around short circuiting application logic if certain conditions are not met.
I have a bunch of lists of strings and I need to know if an string is in any of them so I have to look for the string in the first list, if not found, in the second, if not found, in the third... and so on.
My question is: What is faster?
if (string in stringList1):
return True
else:
if (string in stringList2):
return True
# ... #
and so on or using the index() function inside a try / except block?
try:
return stringList1.index(string) >= 0
except:
try:
return stringList2.index(string) >= 0
except:
# ... #
I know the "in" is linear and that usually the python recommendations are "better say sorry than ask for permission" (meaning the second approach would be better) but I'd like to know the opinion of someone more qualified :)
Thank you!
in is the correct way to determine whether something is or is not in a container. Don't worry about speed microoptimization until you have tested your app, found it to be slow, profiled, and found what's causing it. At that point, optimize by testing (the timeit module can be good for this), not by taking the words of internet weirdos.
If you are doing lots of containment checks you probably want to use a set instead of a sequence; sets have O(1) lookup. If this is not suitable to your problem, you might want to use a list and the bisect module, which still offers algorithmic performance benefits over the O(n) sequence operations.
There's a chance what you really mean if any(string in s for s in iterable_of_string_lists) or if string in string_list_1 or string in string_list_2. Nesting ifs is not quite the nicest way to do an operation like you show.
Never ever ever use a bare except:. Always catch a specific exception, in this case except ValueError. Using except: will catch and ignore all kinds of exceptions you don't intend, like a KeyboardInterrupt if the user tries to exit your app or a NameError if you have a typo.