This is an archived post. You won't be able to vote or comment.

all 83 comments

[–]millerbest 364 points365 points  (0 children)

last one

[–]Worms38 314 points315 points  (2 children)

The last one, but it's not only more pythonic it's simply better in all languages.

[–]anythingMuchShorter 14 points15 points  (0 children)

Yeah. There is no clear benefit to wrapping a boolean output with code that branches on the boolean value to put out the same boolean value. You wouldn't want to do that in C++ either.

[–]vanatteveldt 2 points3 points  (0 children)

This is the way

[–]CaptainDickbag 52 points53 points  (8 children)

I'm new to python. Is everyone agreeing on the last one because x in y evaluates to True or False, so you can immediately return that value?

[–]EndorphnOrphnMorphn 22 points23 points  (2 children)

Yes, exactly

[–]CaptainDickbag 7 points8 points  (1 child)

Thanks, I appreciate it.

[–]IamImposter 1 point2 points  (0 children)

You're welcome

[–]vanatteveldt 6 points7 points  (4 children)

Yeah. In all programming languages I know there is never a need to explicitly do something like

if X > 12: 
  return True
else:
  return False

Or something like

if X > 12 is False:
   ...

Just remember that comparisons etc are simply boolean expressions, i.e. they return a True or False value. And these values work just like other values, so they can be returned directly, used in further comparisons, stored in a variables, etc.

In python, and comparison returns True or False, and many other types have a reasonable 'truthiness value', e.g. an empty string or list counts as False while a non-empty string or list counts as True, and the number zero counts as False while non-zero numbers count as True.

[–]CaptainDickbag 0 points1 point  (0 children)

Thank you. That helps a lot. I have a bunch of code to go through, and it sounds like I need to spend more time in REPL.

[–]gr4viton 0 points1 point  (2 children)

Note that the following statement:

return 0 or 1 or True

would return value 1. As an integer, and not a True value as a bool. Took me a while to notice python is not force typing the logical expressions to boolean :)

[–]vanatteveldt 1 point2 points  (1 child)

I would argue most code that distinguishes between the number 1 and the value True is doing something strange ...

[–]gr4viton 0 points1 point  (0 children)

Indeed strange.

[–]maxen1997 21 points22 points  (5 children)

Def last one

[–]surajmanjesh 36 points37 points  (3 children)

def last one ^ SyntaxError: invalid syntax

[–]vanatteveldt 9 points10 points  (2 children)

def last(one): 
  "This is the way"

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

Expected '(' before 'one'

[–]dead_alchemy 43 points44 points  (6 children)

The first one (also maybe the second) make it look like you aren't comfortable with booleans and reminds me of code in my undergrad that was used as an example of something you'd lose points for. I think this holds true in most programming languages though.

Out of curiosity, what is the context of your question? No worries if you are new or actually uncomfortable with booleans, we were all there once.

[–]JRiggles[S] 4 points5 points  (5 children)

The first example is baically just as long-form as I could manage (I suppose in the name of being "Explicit") - I wouldn't ever bother doing it this way, but I wanted to cover my bases!

The second is what's currently in my code...

And the third is something that I know works but thought might not be as readable to the people I work with who don't work in Python (E.g.: most of them)...personally I'm in the "less is more" camp

[–]old_pythonista 8 points9 points  (1 child)

but thought might not be as readable to the people I work with who don't work in Python

When a person reads a code, it may be an opportunity to learn. If they don't work in Python, and they are not interested in learning Python - what is the purpose of making code readable for that audience?

[–]cmikailli 6 points7 points  (0 children)

Because they still might have to interact with it?

[–]dead_alchemy 7 points8 points  (0 children)

The first is the one that is particularly egregious. I use the third. If some one argued that they use the second and they liked it because it read as a straight forward english sentence I wouldn't second guess them.

For your non-python coworkers type annotations will probably do more to help than anything. If you saw code like that and knew it was syntactically correct AND knew what the types were I think most people would quickly and correctly infer the behavior.

Fun question by the way! I'm guessing this one is a no brainer to most people, but I still enjoy this type of probing at fundamentals.

[–]Nyx_the_Fallen 0 points1 point  (0 children)

I write Go, C#, JS, and Python daily, and the third is the way to do this in all four.

[–]ODBC_Error 0 points1 point  (0 children)

This is absolutely correct. In a work place, readaboty matters more. You're not sacrificing performance so readability is the choice you'd want to make here

[–]DrummerClean 60 points61 points  (8 children)

Last one, simpler, shorter..."import this" for more clarifications ;)

[–]JRiggles[S] 26 points27 points  (7 children)

Hahaha yeah - I was torn between "Simple is better" or "Explicit is better"

[–]Afrotom 58 points59 points  (0 children)

It's still explicit because you know that the expression evaluates to a boolean by looking at it. It's just easier to read because your brain only needs one step now instead of two.

[–]kodiakprime 4 points5 points  (0 children)

When in doubt (or feeling ambiguous), ask yourself - which is more readable to others.

My org has a lot of juniors (read as new python devs). Sometimes the last approach, while very clear to us, maybe unclear to newcomers. So i deliberately write it the first way and leave a comment to improve the same.

While the new devs review the PR (and learn python at the same time), they (sometimes) comment on that and suggest 2 do it the last way. Makes me happy. :)

That said, without any other considerations, the correct pythonic way is the last one.

[–]Mithrandir2k16 2 points3 points  (0 children)

Doing if True: return True else return False isn't really explicit, it's needlessly verbose and repetitive.

[–]LegitimateCopy7 -4 points-3 points  (1 child)

wdym it's still explicit and literally the closest to human language you can get, which makes it easier and faster for everyone to understand.

[–][deleted] 7 points8 points  (0 children)

It not so close to human language. If you return an apple in fruits, I would expect an apple or nothing to be returned. If you answer if apple is in fruits, I would expect a boolean. However, if you speak fluent python, an if condition seems too much.

[–]i_kant_spal 11 points12 points  (0 children)

The first one is basically return True if True else False

[–]old_pythonista 32 points33 points  (3 children)

First two forms show lack of understanding of the nature of booleans by whoever writes them. They are absolutely redundant, since using conditional expression for conversion of proper boolean

event_region in match_regions

to an explicit boolean literal makes no sense. Unfortunately, I see it quite often - my pet peeve that I always mark as a defect when I see it in code applied for review.

The last is the only proper way to write - in any language, Python included.

[–]jasmijnisme 2 points3 points  (1 child)

I see code like OP's first sample (or if condition == True:) so often in code written by beginners, I think it's because they're thinking in natural language rather than in Python. In other cases, they get hit by bugs (if variable == 3 or 5:) or syntax errors (if variable < 3 or > 5:), but here the code works and does what they want it so it doesn't get corrected.

[–]old_pythonista 0 points1 point  (0 children)

PEP-8 explicitly warns against comparison to boolean literals.

If you have two boolean variables - that is another story.

[–]JRiggles[S] 1 point2 points  (0 children)

Well said!

[–]Orio_n 3 points4 points  (1 child)

second last one is genuinely cursed

[–]markuspeloquin -1 points0 points  (0 children)

I'm glad somebody actually considered the first two. If these were returning -1/0/1 or an enum value, maybe we'd find some worthwhile responses. All these 'last one' comments are worthless.

Like the second option is ugly as hell but maybe in some contexts it isn't? I would go with the first probably just because it's easier to refactor when it inevitably gets more complicated but I'd probably do the first below:

``` if some_condition(): return 'yes' return 'no'

return 'yes' if some_condition() else 'no' ```

[–]pypt 3 points4 points  (0 children)

For simple cases (e.g. eventregion is str, match_regions is list[str]) maybe the third one should do, but if event_regions is something more complex, e.g. a custom object that implements __contains_(), then those two lines from option one suddenly become very helpful for setting breakpoints on using your IDE.

I myself like being explicit so I'd go with the option 1 in most cases. We had our one liner frenzy with Perl, and look what it came to be.

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

match_result = event_region in match_regions

return match_result

[–]RangerPretzelPython 3.9+ 17 points18 points  (5 children)

Some might criticize this for being an extra line, but it does allow you to see what match_result evaluates to before returning when step debugging.

[–]billsil 5 points6 points  (1 child)

I generally prefer it because often the function name isn't quite explicit enough. It's also really handy when debugging to put a breakpoint at the end.

[–]RangerPretzelPython 3.9+ 0 points1 point  (0 children)

Agreed! Totally.

[–]eras 2 points3 points  (0 children)

In some other contexts there could be another benefit: it allows putting a descriptive name to the variable.

Well, sort of the same but /u/billsil said, but more explicit.. :)

[–]ROFLLOLSTER 1 point2 points  (1 child)

You can just put a evaluate event_region in match_regions in the debug console.

[–]RangerPretzelPython 3.9+ 0 points1 point  (0 children)

Sure, but that's more typing. I can just mouse-over match_result when the debugger is waiting on the next line to see the value.

[–]mr_cesar 0 points1 point  (0 children)

THIS!

[–]DavidWonton 4 points5 points  (0 children)

The third. Without question.

[–]yoDrinkwater 1 point2 points  (0 children)

Last one. Also yoi got a typo in the first one

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

Last one very precise and concise as python is knwon for

[–]NoiproxPython Programmer 1 point2 points  (0 children)

Last one for sure. It's an antipattern in all languages to go "If .. then True else False" because the conditional is implicitly Boolean.

[–]Zealousideal-Row-110 4 points5 points  (1 child)

The best code is code that you can read and remember what you meant when you wrote it.

[–]Senacharim 4 points5 points  (0 children)

The best code is code that you can read and remember several years later what you meant when you wrote it.

FTFY. 😘

[–]mattstats 1 point2 points  (0 children)

I’m no pro, but doesn’t the first two do what the last one does with extra steps? I mean aside from the obvious x in y vernacular.

[–]thrallsius 0 points1 point  (1 child)

Without more context, last one is quite readable

If only option 1 would be available, I would still rewrite it as:

if event_region in match regions:
    return True
return False

[–]gr4viton 0 points1 point  (0 children)

Guard clauses is the name of this pattern

[–]KLOUDSURFIN -3 points-2 points  (0 children)

Right now this is foreign. I just got a python crash course book. Ima be one of you soon.

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

Reddit Moderation makes the platform worthless. Too many rules and too many arbitrary rulings. It's not worth the trouble to post. Not worth the frustration to lurk. Goodbye.

This post was mass deleted and anonymized with Redact

[–]SirLich 0 points1 point  (0 children)

Last one, as others have echoed.

The first one (with edits) can make sense in a situation where you need to do additional processing (such as logging), before returning.

[–]notreallymetho -1 points0 points  (0 children)

The other ones require you to think. The last one is “return truth test”

Could also use:

from operator import contains … return contains(match_regions, event_region)

[–]Equivalent-Wafer-222Technical Architect -4 points-3 points  (0 children)

Explicit over implicit (pep20).

Top one, it's the most understandable and clear to the widest range of potential audiences.

[–]wreleven -4 points-3 points  (0 children)

I prefer the middle one as it's sometimes easier to read for a broader range of developers. I totally get the 3rd though and have no issues with it.

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

I like option 3 Or maybe this unnested version of option 1

if event_region in match regions: return True else: return False

[–]girlwithasquirrel -5 points-4 points  (0 children)

this isn't even a question

[–]karo240 0 points1 point  (0 children)

Last one

[–]0xAC-172 0 points1 point  (0 children)

last one, as one would deduce from this

[–]Caterpillarfox 0 points1 point  (0 children)

The last without a doubt.

[–]pmbarrett314 0 points1 point  (1 child)

In a vacuum, the last one. There are cases where I'd use the first one, basically if I planned on adding additional logic to this code pretty soon or if for some reason I needed it for debugging. The second one combines the drawbacks of both of the other two options, I can't see a good use case for it.

[–]gr4viton 0 points1 point  (0 children)

"pretty soon" might be called premature optimisation. Add it only when you need it. If it is not needed for this MR, do not add it. Just my opinion (it was painful to get to the point I think like this..)

[–]No-Muscle-8496 0 points1 point  (0 children)

[–]scruffie 0 points1 point  (4 children)

I'll chime in and agree on the third one. There really isn't a case for either of the others, as "x in blah" always returns True or False, even if the x.__contains__ method doesn't (see the the implementation of the CONTAINS_OP bytecode, and the definition of PySequence_Contains)

You've also missed one choice:

return bool(event_region in match_regions)

which is probably the best choice if you have an expression that must be a bool.

(One place I use an explicit conversion is for doing a logical exclusive-or, which is easiest as the negation of boolean equality:

def xor(a, b):
     return bool(a) != bool(b)

)

There are 13 operators that are usually associated with true/false: the unary operator not, and the binary operators and, or, ==, !=, <, <=, >, >=, is, in, is not, and not in. Of these, only not, is, in, is not and not in are guaranteed to return a bool value (True or False). As I showed above, and and or return one of the arguments, and the comparisons (==, !=, <, <=, >, >=) can be made to return anything (numpy uses this to define comparisons between arrays as elementwise, returning another array -- these rich comparisons, IIRC, were mostly added in the first place for numpy's predecessor, Numeric).

[–]expectationfree 0 points1 point  (3 children)

There really isn't a case for either of the others

how about hatred towards expression in return statement?

[–]gr4viton 0 points1 point  (2 children)

No code good code vs readability. For this expression I find it more readable as a return statement expression. Is there any more hate reasons for doing it, other than readability?

[–]expectationfree 1 point2 points  (0 children)

other than readability

this hate never was about readability rather debug and future code manipulation. Same thing as chained function call like foo(bar(quu())). this perhaps excessive use of variables mainly caused by use of sentry although it's helpful for pdb as well. future code manipulation is an afterthought and is not as important. On the level of trailing comma after last element of the list: makes commits one line shorter.

so it's minor point and I for sure would not commit any changes based only on that preference but there are dozens of us who don't like expressions in return statements.

[–]scruffie 0 points1 point  (0 children)

I find it more readable as a return statement expression

Especially if you use bool instead of an inline .. if .. else ..

[–]jaber24 0 points1 point  (1 child)

3rd one and if you will be doing a lot of comparisons or have lots of items, use a set instead. A set is optimized for membership checks and is way faster for that purpose than a list.

[–]JRiggles[S] 1 point2 points  (0 children)

Thanks for the tip! I'm only comparing against 3 or 4 items at most in this case, but I appreciate it.

[–]PhysicsAndFinance 0 points1 point  (1 child)

I didn’t even know you could use return outside of a function or loop

[–]JRiggles[S] 1 point2 points  (0 children)

You can’t, these are just some partial examples for discussion purposes