I agree. The more mature developer understands all languages have their strengths and weaknesses. I really like Python myself, and it's in my top three list of languages I like (Scala, Ruby and Python -- not in any order).

Even PHP, which is not a well designed language at all, has at least attempted to make core language improvements in PHP7 and has supersets like Hiphop/Hack which use the same syntax and avoid most of the insane typing pitfalls.

And in this case, the reality is the ternary operator is just a pretty bad syntax. Most teachers generally tell you to stay away from them and a lot of style guides do too.

Python tried to make it more english-like just like many other of it's syntax (using and/or/not instead of && || !) and in this case it feels strange to experienced programmers who are not used to it. That being said, if you show this and javascript one to someone who's new to programming, they'll for sure understand the Python one better.

Still, again that's where style guides come in. I've been coding Python for years and rarely ever used the ternary.

I can't think of a language that belongs less in that dichotomy than Python. Programmers used to gush over it like crazy; they only stopped because it became ubiquitous enough that there was no point. Javascript, PHP, and C get an order of magnitude more hate.

The difference to me about this is that it seems PEP308 was explicitly created to spite those wanting a conditional operator, whereas many other "incredibly poor design decisions" like e.g. PHP's conditional operator having the wrong/unintuitive associativity happened more accidentally/without explicit intent.

Python is an imperative language. The control structure, based on indentation, is well matched to Python's imperative character. Attempts to retrofit a functional style to Python fit Python's syntax badly. Lambdas, conditionals, and list comprehensions look painful if they extend beyond one line, because the indentation assumptions of Python just don't fit.

As a practical matter, only use Python's functional features in one-liners.

Indeed. I find the huge "some_method" example pretty much invalid because I'd assign that dict to a variable first, so the line would be a nicer "return my_dict if y else {}". What person, style guide or PEP is forcing anyone to write some_method's return statement?

I don't get the ideal of saving space and writing huge one-liners (that in Python you'd have to break up over more lines). As they say on IRC: "if you're worried about using too many lines, I can send you a file full of blank ones."

I'm not sure why the author calls the two branches of in if/else the consequence and the final_consequence. That naming suggests that you do both of them, with the latter coming after the first, which is of course not how an if/else works.

I'm sure that nearly everyone reading the article knows how an if/else works, so that naming won't actually lead them astray, but it just feels ugly.

The difference between Ruby and Python here is that Ruby has a perfectly functional ternary operator that works as one would expect. It also allows some other crazy syntax which can be appropriate in some cases, but it doesn't force you to use it in all cases.

Python does force you to use their awkward conditional expressions; there is no normal ternary operator.

There's a big difference between a language which lets you write hideous code, and a language which forces you to write hideous code.

Is that intended as a defense of Python's ability to enable clear, concise, expressive code? :)

More seriously: Yes, you are obviously correct. But while you can use if/else, you can't use a ternary, and you can in Ruby. That's why people complain about the lack in Python but don't wrote the same article about Ruby.

"Clear, concise, expressive code" isn't something that applies to ternary operators. They were always meant as shortcuts and, as such, will never be as clear as if else statements, practically by design.

You can definitely use too many ternary operators, but I think when used sparingly they can be clear and tasteful. As long as you don't start nesting them or repeating them one after the other you should be fine.

The trailing if can sometimes be confusing in Ruby but the else clause is the thing that's just blatantly anti-intuitive about the Python syntax at issue. Ruby doesn't allow else there because that would be insane. Python chose the insane convoluted and confusing syntax over a well understood and accepted ternary operator.

I use ruby's trailing conditionals exactly this way all the time - it makes me happy to see someone else using the same pattern. I also use it at the start of functions in order to sanity check arguments:

I agree that it reads naturally, but when dealing with those kinds of sentences, they always need to be put into conditional form (A->B). Even when reading text the order of those words matters. Consider:

As a fellow member of the hates-Python-but-not-enough-to-quit-my-job-over-it club, comprehensions are just the worst. Uses variables before defining them, can't be readably broken over multiple lines, overloads multiple pieces of syntax, reads inside-to-out instead of left-to-right. Ugh.

1: When I hit the opening bracket, I don't know whether I'm looking at an array literal or a comprehension. I have to read ahead a few tokens to disambiguate.

2: When I hit `transform(bar)`, I don't know what `bar` is either. I have to jump forward to disambiguate again.

3: Once I hit `for bar in` I realize I'm in a comprehension, but that's still not enough to figure out what `transform(bar)` is acting on. I have to read to the end of the `if` condition, then backtrack to the beginning.

bonus reason: why not `list(baz)`? Is there actually some logic to when Python uses methods and when it uses global functions? If so, please tell me.

another bonus reason: when I was learning Python, I found the keyword reuse genuinely confusing. I would try to write for loops like `for x in my_list if condition(x):` and couldn't figure out why it didn't work because I knew I had seen that syntax somewhere before.

Now, your particular example isn't that bad, but if you make it just a little more complicated you get something like this aberration:

foo = [transform(bar) if bar.property else bar for bar in baz.list() if condition(bar)]

Nothing will convince me that you're not a mutant if you think that's clear and concise.

> When I hit the opening bracket, I don't know whether I'm looking at an array literal or a comprehension. I have to read ahead a few tokens to disambiguate.

All research I have seen says that proficient readers of a language read closer to a line at a time than a token at a time, so I suspect that not really a problem so much as a rationalization of aesthetic preference.

> bonus reason: why not `list(baz)`? Is there actually some logic to when Python uses methods and when it uses global functions?

list is a built-in type, and (as is usually the case for Python types) list() is the type constructor. There are other global functions in Python and there is room for debate over whether they make sense over methods, but constructors for built-types are pretty clear.

baz.list() is a method on baz. Assuming baz is iterable, list(baz) is valid, it's just different than baz.list().

Filters and ternaries aren't the same kind of thing (ternary if/else are analogous to SQL SELECT-clause case statements, filter if is analogous to SQL WHERE-clause; the positions in Python conditionals, which are very much like SQL SELECT statements, follows that analogy.)

I come from a mathematics background and when I first saw comprehensions I really liked them. They read remarkably similar to Set Builder Notation [0]. I think so long as you don't go crazy they are perfectly readable. But at the end of the day the onus is still on the developer to ensure their code is readable.

Bachelor's in math myself, although my math interests and my programming interests have admittedly (and regrettably) not intersected very much in my career. I do tend to think about problems more "imperatively" in my head and then struggle sometimes to translate those concepts into declarative math notation when doing proofs; if I were able to make that leap more naturally maybe I'd benefit from the notational similarities more.

ruby blocks are exceptionally difficult to rationalize at first (well, at least they were for me). I get that they are beautiful (because they are) but it was a major stumbling block on my way to understanding ruby.

A cute feature of this syntax: in "p if c else q" you can think of "if c else" as an infix operator like + and the rest. This operator has an algebra worked out by John McCarthy -- e.g., it's associative. Of course I doubt this will help the poster to like Python more, but it might amuse others.

I've been doing Python professionally for 13 years (among other languages, but Python is in the one I've used more). I like the language but I also hate some things (mainly, the GIL, the lack of static typing now lessened thanks to mypy and the slowness), but I never tough of the ternary if as evil or found a single instance where it confused me.

I like Java, Javascript, Go (which holds a special place in my heart), and C++ even. And I'm being a bit hyperbolic -- I don't hate Python, but sometimes I feel that the language works against you, and not with you.

(but seriously, I don't understand why JavaScript needed the object/primitive distinction. I get it for Java, but not in JS.)

> sometimes I feel that the language works against you, and not with you.

JavaScript is the language where you ask it, "here, I want to know which of these guns most adequately shoots my foot."

ES6 improves things considerably; in 10 years we'll have good browser support for basic data structures, like Map and Set.

[1]: I'm joking. Read it first, then return to this footnote. The sleight of hand is this: the first expression parses as an empty code block, followed by a unary plus taking an empty list. The second parses as binary addition. There's also a terrible amount of coercion taking place. This also "means" that binary addition "isn't" commutative: {}+[] and []+{} evaluate to different values; the same trickery is involved.

[2]: the binary or operator, |, silently converts the operands to a signed 32bit integer for the duration of the expression. Note that signed 32bit integer is a type not available to the JavaScript programmer — it only arises internally! (The only numerical type available is "Number", which is an IEEE double.)

[3]: the grammar for functions is essentially "list of statements or function definitions", so function definitions are only valid at the "top level" of a function.

True, JS is a pain in the butt. But I think it's fun: it feels fluid and that you can do almost "anything" with it (for better or worse). In Python, I feel that I'm fighting against arbitrary goalposts or that I'm wracking my brain parsing some logical puzzle (like in the PEP example).

And don't get me started with Java's verbosity. Half the time Java seems completely unusable without an auto-completing IDE.

And in all honesty I am a big Python fan, but only because it seems like the lesser of all evils in programming. There are some great designs out there, but Python is that toolkit that just seems to be pragmatic enough to be useful and idealistic enough (hello, significant whitespace) to encourage expressive algorithm design.