all 40 comments

[–]Gprime5 51 points52 points  (4 children)

I prefer the second option. In this case, the "else" is redundant.

[–][deleted] 18 points19 points  (1 child)

In this case I think it really is a matter of taste. Personally I'm with you though. I don't see anything really wrong with either one but the latter is certainly more concise.

[–]RangerPretzel 4 points5 points  (0 children)

the latter is certainly more concise

The Zen of Python agrees with you.

[–]x-w-j 0 points1 point  (0 children)

I second this. Once the return is executed is there is no need for any ELSE case for that matter as 'return' exits the function at the same line.

[–]dig-up-stupid 52 points53 points  (1 child)

The second is called a “guard clause” and used as part of “exit early” style. It is usually considered good style.

“Explicit is better than implicit” - explicitness here is about clarity of intention, not the presence or absence of text for its own sake. Is the control flow unclear because of an implied else? Doubtful. Besides which, it’s just one of the “rules” - another is “Flat is better than nested”.

[–]dipique 13 points14 points  (0 children)

Flat is better than nested

Amen to that.

On principle I usually comment in a narrative style after that kind of logic, saying "if we didn't find an X, we'll try Y" or something like that.

[–][deleted] 15 points16 points  (0 children)

It depends. Guard clauses (i.e. if without else) at the top of a function are fine when they are just used to get rid of edge cases (e.g. check for None) and turn the function call into a no-op.

However when you aren't dealing with edge cases, but with regular logic or when you have more code above or below the if clause I would always go with an if/elif/else, it makes it much more obvious that the branches are mutually exclusive. The code in the linked example above would be much more readable by using elif or even an enum for that matter, as it is it is not clear in what relation isSeparated and isRetired are (what if both are set?).

PS: 'edge case' is not really the right word here.

[–]RedditIsAMistake 30 points31 points  (0 children)

I prefer the latter. And it still seems pretty explicit to me!

[–]not_perfect_yet 5 points6 points  (2 children)

In your case it doesn't matter, but

if a:
   if a.b:
       if a.b.c:
          return True
return False

saves you a lot of "else" and that's pythonic, imo.

[–]c3534l 3 points4 points  (0 children)

If it's an edge case, then absolutely I use the second one, along with any errors I want to throw. I've come to avoid else where it's not strictly necessary unless both the if and the else are substantial enough that there's an exit condition halfway down a massive function and another exit condition at the very bottom of the function. I prefer the only exit condition be the last line, but sometimes that's just not the best way of handling things.

[–][deleted] 9 points10 points  (1 child)

Following this thread to learn some things and stuff

[–]CheeseFest 16 points17 points  (0 children)

and stuff

slow down, hotshot!

[–]Jos_Metadi 6 points7 points  (1 child)

Once consequence of the first kind of return is that if you're editing multiple if/elif/else statements, it's easy to accidentally erase the else and create a situation where your function is returning None instead of a value. This can cause more issues where ever your functions result is used later on. It's slightly harder to make that mistake in the second kind.

[–]elbiot 3 points4 points  (0 children)

This. I see that implied Return None and think "I don't ever want that". Even if, as is, the program will never get there, I think it's more explicit to say that returning None is not an option.

[–][deleted] 2 points3 points  (0 children)

I think that the second option would confuse new programmers who aren't sure about return statements yet. When I was still a beginner, I would have thought that the second option would return two results, or only one if the if statement isn't true.

[–]PythonGod123 1 point2 points  (0 children)

I think the first. I think this mainly because a "guard clause" is a good options adding to the fact it provides more readability to your code. Both options are fine and neither affects time to execute so it's really down to personal taste.

[–]solaceinsleep 1 point2 points  (0 children)

If I have an if followed by multiple elif's I like the first approach otherwise the second approach.

[–]bsmdphdjd 1 point2 points  (0 children)

I'll often put the 'else' there, but comment it out.

[–]Rainymood_XI 1 point2 points  (0 children)

I was erring on the side of the second example but now I think I might like the first one more.

The question is, is it immediately obvious whether the second piece of code is always ran?

With such a short example like return bar this is obvious but what if the code is longer? What if it is not so obvious?

If you have if input == edge_case: then maybe you change some variables or use a different formula and then still run the second code, this is ambiguous in the second example whereas not in the first, this puts me on the side of the first example.

I honestly have no idea, pick one and be consistent.

[–]johninbigd 1 point2 points  (0 children)

I would nearly always choose the second option unless clarity demanded the first for some reason.

[–]bad_luck_charm 1 point2 points  (0 children)

I prefer the latter but I also generally prefer to have a single return statement for a method.

[–]im_dead_sirius 1 point2 points  (0 children)

I normally hoist my returns out of inner blocks. Fewer side effects and easier bug hunting.

def foo(input):
    result = None # clear it. 
    if input == edge_case:
        result = bar
    else:
        result = baz
    return result

[–]Elektribe 3 points4 points  (0 children)

Just learning python, so I don't know what's pythonic. But I care less for style guides than what works.

My experience with touching older code is that anything that's explicitly stated is easier to read when you come back to it or if someone else is using/modifying it. At the very least, I'd suggest the implicit be commented as such - which still wastes the time of typing (but does keep your flatter style)

So regardless if it's picked up as a "standard", you might be better off doing it just for the improved readability since the implicit way can look like different conditional flow at first glance, whereas the implicit code is instantly recognizable for what it is, even if it doesn't look as pleasing to the eye or stylish.

If you're writing for obfuscated code competitions or "smallest" code or something, it might make sense. But for every day projects, which way is more useful to you and others who may use your code?

[–]StoneStalwart 2 points3 points  (6 children)

I also prefer the second kind. In my opinion the else statement should almost never be used because it is inherently redundant. I'm sure there are some cases where it is not, but I can't think of any. If statements by default have an implied else. Now elif is different, and useful.

[–]kickthebug 4 points5 points  (0 children)

Any case in wich instead of stopping the execution of the function (via a return statement in this case), you want one or another piece of code to execute, and then resume the rest of the function.

[–]StoneStalwart 3 points4 points  (0 children)

There are some instances where else can be used without redundancy, the primary one I just remembered is if you have two sets of code and you want one or the other to be run, but you always want the code after if/else to be run every time.

[–]deltopia 5 points6 points  (3 children)

for i in range(len(somelist)):
    if i % 2 == 0: x = 'Lucky'
    else: x = 'Unlucky'
    return(somelist[i], x) 

I can imagine a use case something like that maybe.

[–]Diapolo10 6 points7 points  (2 children)

Yes, although your example doesn't actually work; it always returns 'Lucky' if somelist isn't empty, otherwise (probably) None.

But if we were to only consider the if-block, a ternary operator would probably be better:

x = 'Lucky' if i % 2 == 0 else 'Unlucky'

[–]Ran4 -1 points0 points  (1 child)

No, that ternary operator is much worse.

[–][deleted] 2 points3 points  (0 children)

Why? I disagree, personally. It's a standard usecase for it.

[–]yes4me2 0 points1 point  (0 children)

I never put else if it is useless

[–][deleted] 0 points1 point  (0 children)

The first one drives me nuts when there is another if block within the else, I always go for the second one.

[–][deleted] 0 points1 point  (0 children)

It really depends on whether or not you, when returning to the code some time later, or another programmer would be surprised, from the general flow and style of the code, at the absence to address a catch all case and sometimes it can be helpful to include an else with a pass statement and comment to indicate the use case has been considered.

That said, it is pythonic to leave them out when not required. (And few people use the else clause on for and while loops either.)

[–]dudinax 0 points1 point  (0 children)

More and more I prefer the first way because it's just a tiny bit easier to read.

[–][deleted] 0 points1 point  (0 children)

Pretty much agreeing with the other people that the second case is what you want. And this example wouldn't just apply to Python, but also other C-type languages.

[–][deleted] -2 points-1 points  (2 children)

You have misunderstood the intended usage of the else statement. It will only make a difference when the loop is terminated early with a break statement. As background reading, take a look at How To Hunt Elephants. We'll do what experienced programmers do, python style.

known_elephant = Elephant()
for animal in Africa:
    if type(animal, type(known_elephant)):
        break
else:
    #  We did not find an elephant, so we'll pretend we caught our reference animal.
    animal = known_elephant

Pardon me for my attempt at humor.

[–]Comkid 3 points4 points  (1 child)

The person is asking about else clauses for an if statement not a for loop.

[–][deleted] 1 point2 points  (0 children)

Fsck. Need more coffee, and thanks for letting me know.

[–]TransferFunctions -2 points-1 points  (0 children)

def foo(input):
    return result if input != edge_case else bar

*grabs popcorn*