What happened?

Remember when Python looked like this?

def hello_world(name):
    print 'Hello', name

Python 2.7 is a fantastic language for beginners and experts alike. It's so simple and readable that it's sometimes referred to as executable pseudo-code.

At some point a few years ago, things changed for the worse.

Did Python sell out? I don't know. Maybe Guido caved to some persuasive people with bad ideas. Maybe communists, wanting to reduce global productivity, railroaded through all these garbage PEPs. Maybe Python wanted to throw off its reputation as a toy language and become a serious language like Node.js... Whatever the case, when I look at all the PEPs that have been accepted over the past couple years, I can see that the inmates are now running the asylum.

You don't even need to look at the PEPs, though. Just look at the code:

@coroutine
async def hello_world(name: str) -> str:
    await print('Hello {}'.format(yield from name))

OK, that's not exactly valid Python, but it captures the new language aesthetic.

Asyncio

photos/s1487086142.16.png

How to add 2 integers, asynchronously

The language, which was once simple and elegant, has become complicated and clumsy. In my opinion, Python 3.6, with asyncio and type annotations in particular, is an affront to the Zen of Python, particularly:

The garbage fire that is twisted asyncio dramatically increases the complexity of the language. Despite asyncio being just one module among others, one might as well consider it built-in, because it is integrated so deeply in the object model and syntax.

Asyncio is also notoriously complicated. To obtain more than a superficial understanding of code that uses asyncio, you need to be familiar with a whole mess of machinery (event loops, transports, protocols, futures, tasks...). And worse, that's a whole mess of code that needs to be written from scratch, so that the implementation fits in with the asyncio way of doing things. Watch Guido van Rossum struggle to explain asyncio in this video. I don't think even he understands it.

Just look at this sprawling wasteland of components. I included the scrollbar in the screenshot on purpose:

photos/s1487043087.87.png

If you'd like to read an insightful post about asyncio, please check out Armin Ronacher's fantastic essay titled I don't understand asyncio. It's long, but well worth the read.

Python has types now?

In what seems like an April Fool's prank, Python users can now add type annotations to their code. This is in addition, of course, to the annotations you were already adding to your docstrings, and which could be parsed using static-analysis tools. Don't worry, though, all the extra code doesn't actually do anything - it's just for decoration.

Look at this tasty morsel:

from typing import Sequence, TypeVar

T = TypeVar('T')

def omgwtf(l: Sequence[T]) -> T:
    return l[0]

Or how about this memorable function declaration?

from typing import Mapping, Sequence

def notify_by_email(employees: Sequence[Employee],
                    overrides: Mapping[str, str]) -> None:

Python, formerly so austere and easy to read, has become unrecognizable. I'm not even debating the value of type annotations - I'm speaking from an aesthetic point-of-view now. It doesn't seem Pythonic. And why do this when there are hundreds of other languages out there that are statically typed? There are even different flavors of static typing (Java, golang, C), so you can pick whatever you like.

The people who introduced me to Python chose it because of the elegance of the language, and it's aesthetic qualities. Would they choose it again, I wonder? Would I?

Off the grid

I'm sticking to Python 2. For async, I'll use gevent. If I want async magic baked in at the language level, I'll use Node.js or golang. If I want the guarantees of static typing, I'll pick C or golang.

If I want a simple, elegant scripting language that can talk to C libraries...Lua's starting to look pretty good.

Oh and Python 2 is stupid too

No tail-call elimination?


Before you leave a smarmy comment: I'm not criticizing Python 3 as a whole.

Comments (4)

Roger | feb 19 2017, at 12:04am

It's worth adding the main reason Python3 was created (unicode-by-default, and, small cleanups). They didn't get it right. They blame the timeframe of the Python3000 talks, but the correct way to handle unicode is to make everything a byte string, assumed encoding being UTF8. The only way to salvage the situation from all the mistakes is to create a Python4 that removes about half of the standard library (including asyncio and optional typing) and brings Python to a simple, small footprint. That won't happen, because CPython is a toy project for GvR and a small band of rogue developers who don't truly care about good engineering.

Emil Stenström | feb 15 2017, at 01:52am

I don't think asyncio and typing are reasons to stick with Python 2. If you take your initial example, it can now be written as

def hello_world(name):
    print(f'Hello {name}')

... which I think makes a lot more sense. So the language has become better for people that want to keep it simple (most of us), too.

Charles | feb 14 2017, at 02:24pm

The change has been gradual; first there was yield from, now there's async/await, who knows what tomorrow might bring?

The standard library is definitely a mixed bag, but I'd also argue that multiprocessing/asyncore/xml isn't integrated at a language level like asyncio or type annotations are. What makes matters worse is that all this async stuff used to have a separate life as the twisted project -- it's not exactly like this stuff didn't exist until Python 3.5 or whatever. Lastly, lxml has a C dependency (libxml2), while I'm guessing anything in the standard library works with other interpreters.

Ionel Cristian Mărieș | feb 14 2017, at 12:30pm

This might make one believe there was some sudden change of direction within Python maintainership, however, truth be told Python accumulated various now-useless and/or controversial features since the beginning. Things like multiprocessing (simply put, the architecture ain't sound - too easy to get deadlocks), asyncore (now considered arcane), xml (is there something lxml doesn't do much better?) or tkinter (would something like that get accepted into stdlib today? hard to imagine) don't seem much different than asyncio or type annotations.

So by those standards Python 2 is an insane language, just like Python 3. Lets not be hypocrites :-)

The truth is that just like any other piece of software Python accumulates bloat.


Commenting has been closed, but please feel free to contact me