Well, I hate Python. Main points for me: the scoping (or lack of it), the lack of declaration of new identifiers (linked to lack of scoping), the lack of update operators (like `a ||= (i > 0)`), the general lack of conciseness, the `a if b else c` confusion, the weirdness of comprehensions (particularly nested `for`s), the exceptions that are raised for non-exceptional cases. The heaviness of handling exception, like trying to delete a non-existing dict entry (need an additional `if` or a `try` block) or access a non-existing map entry (need to use `.get()` instead of `[]` or a `try` block).
Also, the syntax of layout is bad. I am not talking about layout itself, I do like Haskell syntax (despite being weird about parens). But if I write `a = b +` in Python on one line, then I get a syntax error, although the parser could instead assume that the expression is not terminated and must (obviously) continue on the next (indented) line. I hate that I need to use `\` or `(...)` to make this clear to the parser. I wrote parsers myself, and I know that it knows what needs to follow, and Python itself shows me that it knows: by raising a completely unnecessary syntax error.
It feels to me that the Python language design confuses `simple and easy` with `primitive`. If feels like a design without the knowledge of programming language research and ergonomy. It feels to me like a dangerous toy language, and I am never sure which of my stupid mistakes will be found by the compiler/interpreter, and which will just silently misinterpreted. And which of my perfectly valid requests will be rejected with an exception. In some aspects it feels less safe than C, particularly due to the lack of scoping and the danger of reuse of variables or introduction of new function local variables when actually, outer 'scope' variables were intended to be written.
This is not really meant as a rant, but it is a personal opinion, and I try to lay out my reasons. I am not trying to shame anyone who loves Python, but I just want to clarify that there are people who hate Python.
> the lack of update operators (like `a ||= (i > 0)`)
What would that even do? Is that the equivalent of `a = a or (i > 0)`? Python does not have a "||" operator.
> the `a if b else c` confusion
I'll agree that Python really dropped the ball on implementing a ternary operator, but I guess Guido really didn't want the C version.
> the weirdness of comprehensions (particularly nested `for`s)
If a comprehension is getting weird because of nesting, then I'd change it to not be a comprehension. I'd rather have nested `for` loops than nested comprehensions.
> the exceptions that are raised for non-exceptional cases
I'd be interested in an example of this.
> like trying to delete a non-existing dict entry (need an additional `if` or a `try` block) or access a non-existing map entry (need to use `.get()` instead of `[]` or a `try` block)
I suggest thinking more about the Zen of Python. Specifically, explicit is better than implicit, and errors should never pass silently. If you're trying to delete a non-existing dict entry, or trying to access a non-existing entry, then in most cases, you have a bug somewhere. Basically, Python believes that your code is expecting that dict entry to exist. Forcing you to use .get or use an `if` is a measure to make your code explicitly declare that it's expected that the dict entry might not exist.
> But if I write `a = b +` in Python on one line, then I get a syntax error [..]
Yeah, the parser could certainly be written to handle this case, but it was deliberately written not to.
> It feels to me like a dangerous toy language
Toy language, I could see. Dangerous? Not at all. I could call it opinionated, though.
> and I am never sure which of my stupid mistakes will be found by the compiler/interpreter, and which will just silently misinterpreted.
Meanwhile, I'd look at C and think "I'm not sure which of my mistakes will lead to a memory leak or an exploitable buffer overflow."
> In some aspects it feels less safe than C, particularly due to the lack of scoping and the danger of reuse of variables or introduction of new function local variables when actually, outer 'scope' variables were intended to be written.
I'd argue the exact opposite: It's more dangerous to allow you to accidentally clobber a global variable when you meant to create a local one.
> This is not really meant as a rant, but it is a personal opinion, and I try to lay out my reasons.
I think the core issue is that Python tries to adopt a different paradigm than languages like C, and it's a paradigm that you just strongly disagree with. Personally, I love it. What's funny is that when I first saw Python, I was like "This language sucks, it makes things too easy and it holds your hand." After using it extensively at work though, I find myself saying "This language is great! It makes things so easy and holds your hand!"
Yes, all your points are valid for yourself. It's OK. I did not try to convince you that Python is bad. I only tried to explain why I hate it. In the hope that maybe you better understand why. It's too easy to say 'I hate XYZ', so I tried to explain myself. I am perfectly fine with you loving it. Let's see whether I can explain myself better:
> ... the Zen of Python ... > ... was deliberately written not to ... > ... Guido really didn't want ...
Yes, sure, I do not question that. I am merely saying that I hate many of the outcomes of that. I also hate discussions about that -- it is so quickly sacrilege to hate Python. I know that it's futile to discuss religion, and I am not trying to do that. But someone said that no-one hates Python -- well, I do, and this is why!
> ... explicit is better than implicit ...
Except for variable declarations, apparently. I would very much like them to be explicit, and it would be a start to fix the scoping problem.
> ... Dangerous? Not at all ...
I perceive a danger when the compiler/interpreter does not tell me that I am doing unintended things. Obviously, it cannot know what I intend. But proper and smaller scopes are generally regarded as helping humans to track the visibility of a variable. I certainly cope better with explicit variable declarations and with smaller scopes. I feel a danger that I accidentally misuse (or reuse) variables, e.g. by missing a `nonlocal` or `global` declaration or by using a variable after an `if` that was meant to be only valid local to that `if` block.
> ... Meanwhile, I'd look at C and think "I'm not sure which of my mistakes will lead to a memory leak or an exploitable buffer overflow." ...
Of course C is dangerous, that's why I cited it. But in at least one aspect, the scoping and related lack of explicit syntax to introduce new variables, I think Python is more dangerous than C. In most other aspect, C is definitely worse.
Comparing another language, and how it is possible to improve: JavaScript managed to fix scoping by introducing `let`. If you don't use `var`, then this particular problem is solved in JavaScript.
> ... the exceptions that are raised for non-exceptional cases ...
E.g., 'file not found' in open(). That's not exceptional, because it potentially happens with every usage of open(). You can never seriously use `open` without handling the case that the file is not found. Therefore, it's not exceptional, but it should be encoded in the return value.
> ... then I'd change it to not be a comprehension. ...
That's not the point. I don't want imperative, I want functional. I like list comprehension. I am not complaining about imperative `for`, but I am complaining about the confusing syntax of nested `for` in comprehensions. I am complaining of being forced to use imperative `for` by the weirdly confusing syntax of functional `for`.