Skip to content

Instantly share code, notes, and snippets.

@RobertAKARobin
Last active April 18, 2024 20:44
Show Gist options
  • Save RobertAKARobin/a1cba47d62c009a378121398cc5477ea to your computer and use it in GitHub Desktop.
Save RobertAKARobin/a1cba47d62c009a378121398cc5477ea to your computer and use it in GitHub Desktop.
Python Is Not A Great Programming Language

Python is not a great programming language.

It's great for beginners. Then it turns into a mess.

What's good

  • A huge ecosystem of good third-party libraries.
  • Named arguments.
  • Multiple inheritance.

What should be good

  • 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.

What's "meh"

  • 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.

What's bad

  • 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 a map object, which is pretty much useless since it's missing append, reverse, etc. So, you always have to wrap it in list(), 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 a freeze or immutable method. Speaking of...

  • There's no way to make dicts 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.

What's bad about the culture

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.

@dtonhofer
Copy link

dtonhofer commented Mar 27, 2024

Python is just a worse Perl. And you cannot even retcon use strict into it.

How much worse? I can't say (full disclosure: I like Perl - for some tasks. If code has been written in reasonable ways. With all warnings and strict, i.e. "must declare variable" and related gobbledygook, switched on. And files kept small and everything properly organized into modules.)

Plus the forced indent syntax makes it so that you cannot write one-liners in Stack Overflow comments. Or Coursera exercises. Hah! 😞

But at least it's well documented. That's something that is indeed very important.

Many people say it's somehow uniquely "readable". But "readability" (for reasons of maintainability, or so it is said) should be a concern after "do you have proper static typing". Any-typed mutable stuff rather negates the effort and good intentions.

Plus the forced indentation seems to generate bad feature interactions with the rest of the language design. As in, you want to add something to the language but your indentation requirements block you from adding clean syntax; now what?. And I just found out that it interferes with experimentation, i.e. the "change-and-modify, comment-uncomment loop" that seems to be a necessary ingredient of getting something to work in Python (or, if one is learning, any other language really, try Clojure...)

Python for scripting the odd task, sure. It's much better than bash. But as someone on the Internet (rightly) said, it's very ill-advised, for economic or reliability issues, to try to build large software systems in Python.

And then can anyone rationally explain this:

my_list = ['foo', 'bar', 'baz']

def f():
    my_list = ['qux', 'quux'] # my_list is local to f()!
    my_list[0] = 'ggg'

f()

assert my_list[0] == 'foo'
assert my_list[1] == 'bar'
assert my_list[2] == 'baz'

def g():
    my_list[0] = 'texx' # this accesses the global my_list!

g()

assert my_list[0] == 'texx'
assert my_list[1] == 'bar'
assert my_list[2] == 'baz'

# But the interpreter / (bytecode compiler?) does not like this
# 
# def h():
#     my_list[0] = 'aloha'  # "cannot access local variable 'my_list'"
#     my_list = ['qux', 'quux']
#
# h()

def h():
    global my_list # now we can modify the global list
    my_list[0] = 'aloha'
    my_list = ['qux', 'quux']

h()

assert my_list[0] == 'qux'
assert my_list[1] == 'quux'

I just had to get this off my chest. Enough of this, I have an exercise in NumPy to do 😓 . And then it's over to Dart.

@dtonhofer
Copy link

@KDean-Dolphin

Prolog (1980s-grade psychedelics),

Hah! No, Prolog is absolute genius once you understand how it even works (i had to reset my assumptions).

If there were some serious investment in Logic Programming instead of everyone throwing money at trying to reinvent a square wheel with the whole JavaScript ecosystem (a practical joke, shurely?) one might see some progress in computer science. There are a lot of excellent ideas out there.

Meanwhile, I guess there is Mercury (underappreciated too, needs a proper IDE)

@KDean-Dolphin
Copy link

@dtonhofer

Prolog (1980s-grade psychedelics),

Hah! No, Prolog is absolute genius once you understand how it even works (i had to reset my assumptions).

I’m happy to be wrong. I’ll give it another look, with the benefit of a few decades’ experience.

If there were some serious investment in Logic Programming instead of everyone throwing money at trying to reinvent a square wheel with the whole JavaScript ecosystem (a practical joke, shurely?) one might see some progress in computer science. There are a lot of excellent ideas out there.

I’m with you on JavaScript; it suffers from the many of the same issues as Python, but the language appears to be better managed, and there are some things in TypeScript that I really like. The build system is horrible, though.

Meanwhile, I guess there is Mercury (underappreciated too, needs a proper IDE)

I’ll take a look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment