It's great for beginners. Then it turns into a mess.
- A huge ecosystem of good third-party libraries.
- Named arguments.
- Multiple inheritance.
- It's easy to learn and read. However, it's only easy to learn and read at the start. Once you get past "Hello world" Python can get really ugly and counterintuitive.
- The Pythonic philosophy that "There should be one -- and preferably only one -- obvious way to do it." As someone who loves working within rules and rigid frameworks, I love this philosophy! As someone who writes Python, I really wish Python actually stuck to this philosophy. See below.
- Forced indentation. Some love it because it enforces consistency and a degree of readability. Some hate it because they think it enforces the wrong consistency. To each their own.
- Dynamic typing. There are lots of dynamically-typed languages and lots of statically-typed languages. Which kind of typing is better isn't a Python debate, it's a general programming debate.
-
400 ways (more or less) to interpolate strings. This prints "Hello Robin!" 3 times:
user = {'name': "Robin"} print(f"Hello {user['name']}!") print("Hello {name}!".format(**user)) print("Hello %(name)s!" % user)
If there was a unique and obvious use-case for each of these then that would be one thing, but there's not.
-
69 top-level functions that you have to just memorize. GvR's explanation sounds nice, but in reality it makes things confusing.
-
map
doesn't return a list, even though the whole point of a mapping function is to create one list from another. Instead it returns amap
object, which is pretty much useless since it's missingappend
,reverse
, etc. So, you always have to wrap it inlist()
, or use a list comprehension, which, speaking of... -
List comprehensions are held up as an excellent recent-ish addition to Python. People say they're readable. That's true for simple examples (e.g.
[x**2 for x in range(10)]
) but horribly untrue for slightly more complex examples (e.g.[[row[i] for row in matrix] for i in range(4)]
). I chalk this up to... -
Weird ordering in ternary/one-line expressions. Most languages follow a consistent order where first you declare conditions, then you do stuff based the on those conditions:
if user.isSignedIn then user.greet else error
for user in signedInUsers do user.greet
Python does this in the opposite order:
user.greet if user.isSignedIn else error
[user.greet for user in signedInUsers]
This is fine for simple examples. It's bad for more complex logic because you have to first find the middle of the expression before you can really understand what you're reading.
-
Syntax for tuples. If you write a single-item tuple
(tuple,)
but forget the trailing comma, it's no longer a tuple but an expression. This is a really easy mistake to make. Considering the only difference between tuples and lists is mutability, it would make much more sense to use the same syntax[syntax]
as lists, which does not require a trailing comma, and add afreeze
orimmutable
method. Speaking of... -
There's no way to make
dict
s or complex objects immutable. -
Regular expressions require a lot of boilerplate:
re.compile(r"regex", re.I | re.M)
Compared to JavaScript or Ruby:
/regex/ig
-
The goofy string literal syntaxes:
f''
,u''
,b''
,r''
. -
The many "magic" __double-underscore__ attributes that you just have to memorize.
-
You can't reliably catch all errors and their messages in one statement. Instead you have to use something like
sys.exc_info()[0]
. You shouldn't have a catch-all in production of course, but in development it's very useful, so this unintuitive extra step is annoying.
Most programmers will acknowledge criticisms of their favorite language. Instead, Pythonists will say, "You just don't understand Python."
Most programmers will say a piece of code is bad if it's inefficient or hard to read. Pythonists will say a piece of code is bad if "it isn't Pythonic enough." This is about as helpful as someone saying your taste in music is bad because "it isn't cultured enough."
Pythonists have a bit of a superiority complex.
@Odalrick:
Python didn't innovate though. The trailing
if
idea already existed in Perl (which predates Python by just over 3 years), and it wasn't the best thought-out idea back then either.Certain features become widely copied because they work well, and ternaries are one of those features.
I can't help but find that a bit ironic after the mention of Python not liking 'cryptic symbols'. Especially considering the ternary operator is also from C.
It might read more like English, but personally I prefer Haskell's answer to the problem, which is
c = if a > b then a else b
. It follows the ternary ordering, it's easier to parse, and you can nest it:if a > b then (if a > 0 then a else 0) else (if b > 0 then b else 0)
.(Haskell's answer to the problem actually comes from ML, which predates both Python and Perl. In fact, it's only 1 year younger than C.)
I definitely agree with this. I tend to prefer using an explicit
this
even in languages where it's optional.I'm not convinced that's actually a good thing.
Firstly, it's error prone.
honk
is fine because you're not likely to find ahonk
method that does something other than making a sound, but there are situations where two classes might both have a method with the same name that does something very different.For example, take
+
. As you said yourself, it's commutative for numbers but not for strings, so if you fed both into a function that expected the passed object to implement+
in a commutative way then it could work fine for one but break silently for the other. That problem could be solved if there was some kind of interface concept that had to be opted into, which would separate the commutative adders from those objects that are using+
for something that isn't really addition.Secondly, not having an explicit interface means that instead of specifying a named concept and its rules within the language you end up either leaving that concept vauge and undefined, or having to define it in the comments. By writing a function that expects a passed object to
honk
, the concept of 'something that canhonk
' becomes important and relevant to your program, so callers should be aware of its existance and should be informed enough to know whathonk
is expected to do, and that's easier to manage when you have some kind of interface/typeclass concept.I'm not necessarily saying Python should have something equivalent to interfaces, just that duck typing is error prone and better alternatives do exist.