Ask HN: Why did Python win?

578 points by MatthiasPortzel ↗ HN
I started programming in ~2013 in JavaScript. I’ve since learned and tried a handful of languages, including Python, but JavaScript was always my favorite. Just within the last year I learned Ruby, and I was blown away by how fun and easy to use it is. At the present time, I’m starting all my new projects in Ruby.

My impression is that in the ‘00s, Python and Ruby were both relatively new, dynamically typed, “English-like” languages. And for a while these languages had similar popularity.

Now Ruby is still very much alive; there are plenty of Rails jobs available and exciting things happening with Ruby itself. But Python has become a titan in the last ten years. It has continued to grow exponentially and Ruby has not.

I can guess as to why (Python’s math libraries, numpy and pandas make it appealing to academics; Python is simpler and possibly easier to learn; Rails was so popular that it was synonymous with Ruby) but I wasn’t paying attention at that time. So I’m interested in hearing from some of the older programmers about why Ruby has stalled out and Python has become possibly the most popular programming language (when, in my opinion, Ruby is the better language).

855 comments

[ 2.9 ms ] story [ 392 ms ] thread
Because Ruby was tied to Rails, whereas Python had both a Rails competitor, not as popular but decent enough to be used by several big companies (Instagram, Pinterest, Spotify, Disqus, Bitbucket, and others), plus libraries for science, and later for the rising field of machine learning and even AI.

That said, Python was always more popular than Ruby to begin with (more jobs, more programmers, more college CS classes, more books), even in 2000-2010. Ruby was liked, but was only hot because of the Rails connection.

It writes like English and you don't have to think about memory. Those two things are _huge_.
Python grew out of a myriad of applications that built on hard to replicate components, while Ruby relied only on web development which is remarkably subject to fashion.

Python is very simple making it easy to learn. Thus, it became more and more popular for fields where programming is not the main task, like science. It is also very easy to extend with C. So, these fields could bolt on time-tested scientific code into their Python scripts.

Ruby seemed to be entirely tied to Rails.

When the 00s and 2010s came with needs for web development and scientific computing for big applications (e.g. ads on social media), there were multiple language options for web development but really only one that made it easy to onboard academics into the task of building software systems.

From there, it was just a feedback loop, and when deep learning became a major field, the ML community was already knees deep in Python, so it was hard to justify making tools elsewhere.

Meanwhile, it seems to me, that Rail's appeal (and with it, Ruby) was taken by Node's promise of using the same language on both server and client, and more generally diluted by the fashion waves of web dev.

If you want to swap Python for another language in scientific computing, you will soon find annoyances that certain packages are missing, or don't talk to each other well, or aren't optimized. If you want to swap Ruby for another language, you just use the other language web dev library and that's it.

As an aside, Julia has been the promised replacement for Python for over a decade. It tries and does replicate the package ecosystem, the ease of use, extendibility, etc. It also goes out of its way to be able to use Python packages out of the box. But it just seems to be very hard to convince practitioners to go to Julia for just some small performance changes.

I agree. I've seen Python being taught in Physics and hard science university cursus as an introduction to programming 15+ years ago.
When I was at CERN in 2003 - 2004, it was when the first set of Python introductory courses started.

The build infrastructure for ATLAS used the CMT tooling, written in Python.

The Summer School of Computing 2004 had several sessions related to Python in the context of grid computing.

> Ruby seemed to be entirely tied to Rails.

I’d be interested in going one step further and asking why that was. Rails is great, but so is Ruby, but normally a great library like Rails helps attract developers to the language. Rails is the only example I can think of where a widely popular library (ostensibly) leads to fewer users of the language for other purposes.

Not exactly the same thing but flutter and dart have a similarly weird relationship too.
I wonder if it's because Rails creates such a specific set of expectations that when you actually try to do something without it you run into problems. "Oh, that's only a rails thing? I thought that was a ruby thing..."

Ruby's monkey patching convention might make this worse.

I actually failed a technical interview relatively recently because of this.

It was a fullstack position with some Ruby scripts here and there mostly centered around scheduling. Had a leetcode style takehome that requested I build out a pretty simple reservation system with time off and quarter hours and stuff like that.

I boot up into the leetcode environment and was surprised at just how many things were Rails-specific, rather than being in the ruby STD lib. Completely threw me off since I suddenly had to figure out how to wrestle the Date STD lib to work for me, and anything date/time related is my personal hell :)

> Ruby relied only on web development

Chef, Puppet, Vagrant, Logstash, etc are not web development.

Ruby dominated (dominates?) DevOps tooling.

Back in 2012 there was no question that ruby was the language of DevOps, then Ansible took over. Puppet was a true pain to work with, and through at least version 4, their language designers were simply wrong about what it meant to be a declarative language (you could only declare each resource once, they pretended/falsely believed that inference and/or unification were incompatible with declarative languages), but wow was it powerful to maintain dependable state on long lived servers
I think their comment still holds. Those are all tools that you use, and mostly don't care what language they're written in. When you've got to write Ruby, it was predominantly in the context of RoR.

I think also that dominance has mostly faded. When I think of languages that dominate devops now, I think of Go, and I say that as someone that dislikes Go.

I'm sorry, but for me it seems that Go has is taking the lead in adoption rates for devops tooling.

Ruby isn't the go-to language there anymore... probably because GoLang compiles statically.

The k8s world is Go Central, so that probably has a lot to do with it.
YMMV, but I've only seen Rails fans use any of those.
There was a time when Puppet and Vagrant were head-and-shoulders the best options, and I say this as a JVM/Python guy who never got on with Rails. (I'd argue they still are, but sadly everyone is on docker and k8s these days whether it makes sense for their use case or not)
Ansible is Python, Terraform is Go. Those are 2 giant projects in DevOps.
> Python is very simple making it easy to learn.

I would argue that there's little difference between them in ease of learning. I personally found Ruby easier because everything being an object with methods and no free floating functions felt more natural and easier to look up. i.e.

string.length

over Python

len(string)

It's easier than Java, though, where you have string.length(), array.length and list.size(). In Python it's always len(whatever). But maybe Ruby wins this one if it's consistent in its method naming.
The global functions throw me off too.

To me in general Ruby is the nicer feeling of the two, just generally more "friendly" and "human". Whether those are desirable traits of a language is up for debate but I think there could stand to be more language with such a flavor.

Ruby has implicit imports which pollute namespaces. This is extremely annoying for anyone who wants to learn the language. It uses extensive monkey patching, which is once again a substantial challenge for a beginner that wants to understand what their code is doing. It has a nicer syntax with procs and lambdas but syntactically distinguishes between them with different ways of invoking functions and all the issues associated with bindings. In Python all functions look and behave the same, to the point where methods have an explicit self argument to make it clear that they're just regular functions (the semantics for function binding could be easier but then again such is the case in all object oriented languages).

Python's challenges are superficial syntax; the semantics are extremely uniform everywhere and don't suffer from special cases galore.

I don't think either of those issues, namespaces and monkey patching, are things that make the language harder to learn. You require a file, the file's namespaces are available. How often do libraries modify your runtime with monkey patches in a way that you'd notice? I'm sure it's come up during my career, but not when I was a beginner. There was a period of time when metaprogramming was more popular in the ruby and rails community but that was some time ago. Still, it's a tool that's nice to have available.
I vividly remember how I was told that you could write "2.years" in RoR.

So, if you copy that code snippet and run it as an independent script, it would just not work because it was a RoR monkey patch method.

Worse, the implicit imports mean that unless you have a global view of which files and gems are require-d, you don't know what your code is actually going to do.

That, and coworkers suddenly feeling at liberty to override `method_missing`, abusing `bindings`, and all that stuff, makes it really hard to like the language if only for its tendency to bring out the worst in people.

Requiring a file from a library that's part of a framework's source code can be quite challenging as it requires either the complete docs or perusing the source code to fully grok what's getting included, especially with the monkey patches.

I don't know the current state of the RoR ecosystem but back then when both languages were competing for similar mindshare this was a massive turnoff.

According to David Beazley, it was lucky to already being around by the time scientific computing folks were in need for dynamic languages as wrappers to help with increasingly complex hardware and projects written in lower level languages, and the only other viable alternatives back then were Perl and tcl. Watch this talk: https://youtu.be/4RSht_aV7AU?si=d3rJvYJPFGcRy6BK

Then it just snowballed since that time.

Because Python is not horrible general purpose language. In the end not everything is web.
No language ever won. When I started COBOL had won, not so today. Over the years various languages have won. Python is popular today for many but not all applications. That's about all you can say.
Python is clearly the current winner. Not sure being pedantic about what it means to be a winner adds anything
If there's a winner, it's still named "Java".
I was talking in the context of the Ruby/ Python/ interpreted language world of the parent post
if you're going off interpreted languages then PHP won. it's not as sexy or hot but it powers more websites than anytime else, or JavaScript which is also an interpreted language that is literally in every app so you could say it wins though I'd only count full stack js apps not PHP apps with a Vue frontend.
PHP certainly powers a lot of sites, but there seems to be a lot less code written in it. Maybe I'm just looking in the wrong places. I see tons of python job listings, very few php ones. PHP powers wordpress, and people use wordpress with a sprinkle of custom php it seems.
Frankly, I'm shocked it is not Javascript. It seems like it shows up everywhere.

Maybe it is because we consider Typescript to be a different language? The rise of Typescript has eroded into the use of Javascript proper quite a bit. Standing alone, I could see them being losers to Python overall. But at the same time Python 2 and Python 3 are different languages, yet seemed to be grouped together, so is there justification for Javascript and Typescript to be divided?

(comment deleted)
I think it just survived naturally, filling in the cracks left by Java / C++.

And now the era of Textual (https://textual.textualize.io/) is here, python may get the spotlight even more.

Can you elaborate why we're living in the era of Textual? Genuinely. It seems like a pretty nifty library but I'm not sure it transcends to killer library territory. Thanks!
> My impression is that in the ‘00s, Python and Ruby were both relatively new

They were, but Python is close to 5 years older than Ruby (February 1991 vs December 1995), so in the ‘00s, Python was significantly older than Ruby.

Ruby also was more or less a Japanese-only thing until around 2000. https://en.wikipedia.org/wiki/Ruby_(programming_language)#Ea...:

“In 1999, the first English language mailing list ruby-talk began”

“In September 2000, the first English language book Programming Ruby was printed, which was later freely released to the public“

In contrast, Python was posted on alt.sources from the get-go (https://en.wikipedia.org/wiki/History_of_Python#Early_histor...).

So, effectively, Python had about 9 years head start on Ruby in the English speaking world.

> when, in my opinion, Ruby is the better language

IMO, its flexibility makes it deceptively simple. Certainly, early users used its flexibility a bit too much to implement useful functionality that felt like spooky actions at a distance for newcomers.

> Ruby also was more or less a Japanese-only thing until around 2000

And after that it still took quite a few years until "English support" really became first-class and comparable to Python. I looked at Ruby around 2002-2003 or so (I was looking at many different languages back then, pretty much anything I could get my hands on), and lots of Ruby stuff was in Japanese or poor English.

That's all fine, but I specifically remember that was the major reason I ended up not using Ruby at the time.

(I did end up programming a lot of Ruby many years later, and for what it's worth I do prefer Ruby for most things now)

Ruby’s English documentation remains terrible, unfortunately.
I can't say I've had much trouble with it; I have generally found it more than adequate.
Early on, at least English speaking ruby had an extremely poor culture around documentation. Code was barely commented and "the ruby way" was to use single character variable names
And the culture of metaprogramming and monkey patching didn’t help.

If the documentation is bad you can read the source, but if you need to grok 3 layers of metaprogramming living in unpredictable locations before you can do that there’s no way to advance (practically).

Original asker here, thank you for this comment. Lots of people are arguing about the pure merits of the languages, but the gap in usage IMO is way too big to be explained by “Python has only one way of doing something” or “Python is multi-paradigm.”

Understanding that Python was established years before Ruby was being discussed answers the question of why Python is preferred for many use cases.

> Python’s math libraries, numpy and pandas make it appealing to academics; Python is simpler and possibly easier to learn; Rails was so popular that it was synonymous with Ruby

Yeah, that’s basically why.

Back in its heyday, Ruby had two basic niches. The bigger one was Rails. Rails is still alive today, but after the move towards richer frontends a lot of the hype, and consequently the developers, followed that trend into the JS world. It’s obviously possible to have rich React frontends and Rails backends if you want to, but that isn’t quite what you got with “omakase” Rails.

The other niche was in devops tooling, e.g. Chef and Puppet. But that space moved towards containerization and all of that tooling, more or less, got written in Go.

The recent DevOps tooling is also not conducive to using code at all - it's YAML all the way down. Nobody is writing Go for everyday DevOps now, whereas for a bit they were writing Ruby and Python.
To offer a slightly different perspective than just "ecosystem", I learned Ruby a few years after Python, and found it kind of annoying, in that many Ruby programmers tend to invent their own DSLs and little hacks because the language is so flexible. I know many programmers love Ruby for class_eval, but it really makes codebases hard to read, and code is read more than it is written.

Python has honestly had some opportunities to die out (2->3 transition, type hinting missteps, incredibly slow, etc.) but survived because writing extensions was always easy and it was taught a lot in universities.

I often hear this kind of praise for Ruby but have never really dug into it myself. Does anyone have any links to pages that do a good job of covering some of the main selling points of Ruby in terms of syntax, features, ecosystem, etc.?
Languages that won, win, and will win are all of those that are moving towards being smart, in the sense that the compilers/transpilers infer what the programmer is trying to do and generate the appropriate code under the hood.

The future of programming is describing the majority of programs in something thats even closer to English, and then fine tuning it with something like python, all of which will result in natively compiled optimal binary.

People have been making similar predictions longer than either of us has been alive. Remember Cobol? Basically that. 5th generation languages? Same thing, with a different definition of "describe". Ultimately, those all turned out to be dead ends while the "antiquated" languages kept improving and innovating, albeit usually by (re-)inventing things that already existed elsewhere.
You are mistaking syntax for features.

C++ got popular because it managed data structures under the hood automatically. I.e, you didn't have to keep track of memory offsets or function pointers.

Java got popular because it did that and also managed memory allocation under the hood automatically.

Python (and Javascript) got popular because it did all of that and also managed types under the hood automatically.

The future is exactly this. Some language (or Python 5 or 6) is going to do all that except manage common processing algorithms for you automatically. For example, you will not need to import a library to convert xml to json, the .toJson call will be put through an AI inference algorithm that will essentially generate the required code for you on the fly, and more then that, it will do it in a much optimal way because it will recognize that the xml data follows a particular structure so it can optimize the search of the tags rather than doing a generic approach.

The discussion isn't about C vs Python, it's about why Python won over Ruby, a language at a similar level of abstraction. Ruby is arguably even less burdensome because in many cases the libraries/frameworks do a lot of magic that would be unpythonic.
Ruby has a lot more idiosyncracies, especially with cross platform stuff. Like I said, the more the language does for you, the more its going to "win".
AFAICT, Python won over Ruby because the support was largely in English, not Japanese, and because English is the language of global science and commerce and Japanese is the language of…Japan. Boosted by Python having a much better experience on the most common desktop environment (even though Python also favored Linux and, IIRC, other Unix-ish environments); Ruby experience on Windows eventually got tolerable, but even now that’s largely because there is a third-party project providing the main Ruby-on-Windows installer.

The overwhelming advantage in ecosystem breadth and depth it had for this reason was insurmountable, even once Rails drew more attention to Ruby. There’s a whole bunch of technical advantages and disadvantages of each when you look at the language and core implementations, but I don’t think they were really the factors that led to the different relative popularity of the two.

Javascript got popular because it was the only option to program for the web. That's it.

Python and other dynamic languages don't "automatically manage types", they just let you not write the types down in the code. The types still exist and need to be managed by the programmer. There's zero cognitive load improvement there.

As for the AI stuff, lol. I see no point discussing concepts so far out of reach they're in the realm of sci-fi. What you're describing is just magic compared to what we can do in 2023.

We already have languages that automatically pick the best algorithms by the way, in the form of declarative languages like SQL. They don't seem to work very well outside of the realm of fetching data from databases.

>Javascript got popular because it was the only option to program for the web. That's it.

If it wasn't as flexible as it was, another language would have taken it over.

>Python and other dynamic languages don't "automatically manage types", they just let you not write the types down in the code.

They do. They carry dynamic type information during runtime, and can be modified during runtime.

>What you're describing is just magic compared to what we can do in 2023.

Then you must think that stuff like branch prediction, and compiler optimizations are magic as well.

It never seemed to me that "ADD 1 TO COBOL GIVING COBOL." was a good idea. (FORTRAN, on the other hand, made a lot of sense.)
I always thought of Ruby as Perl++ more than anything. It's relatively easy to write, not always so easy to look at and refactor later. As to why Python has won, I think you nailed it, the library integrations and academic space has made it popular and useful there.

Ruby's popularity for what it was, was heavily tied to Rails. As that space progressed, a lot of people came to dislike it as much as anything, and maybe more. There are a lot of ways it didn't work so great and those warts made more and more avoid it in future projects.

That's my $.02. I started with JS as well, but in '96 and through classic ASP (JScript and VBScript) through VB6, .Net (and C#) then into/through Node.js etc. I also dabbled in PHP, Ruby and a handful of other tech along the way. Python feels like a massive gap in my knowledge base at times, I have a few books to read, but not much in terms of opportunity/need. And the time I've spent on Python, I feel like I'd rather spend that time leveling up in Rust.

Coming from Perl, I love Ruby (for non-Rails stuff), but end up using Python because:

- The documentation in the Python ecosystem is generally better.

- There's more Python libraries, and they're generally better maintained and better documented.

- Python has a better interface to C.

- Python is more popular and generally more supported by third parties.

- Django/Flask

- There is comparatively little Ruby activity outside of Rails and a few cybersecurity projects.

I really do not like Python. I think it's really inelegant. But it's a better tool for getting my tasks done, due to the above reasons.

I also had a hard time choosing between Python and Ruby for my goto scripting language. But given Python community is more active outside of webdev, I also chose to stick to be more professional on Python.
It has very little to do with Python itself. Python won because GvR ran an extremely tight ship. And there were many extremely talented core developers that helped make Python a polished product. The development team made all the right decisions, except for rejecting PEP 355 which was a big mistake. The batteries included approach helped grow the ecosystem. Developers wrote third party libraries in the hopes of them eventually, someday be incorporated into Python's standard library. Python also came in an msi installer and made the Windows experience pleasant, unlike Ruby and Perl which iirc were painful to get up and running.
> PEP 355

Didn't this eventually become what is now pathlib (which I am a big fan of) ?

pathlib is truly excellent! The overlap with the os library is unfortunate, but I can’t complain.
> except for rejecting PEP 355 which was a big mistake

Looks like you are the author of PEP 355. Well, we got pathlib in the end. It's not that bad.

> Python also came in an msi installer and made the Windows experience pleasant

For a long time, the official Windows Python distribution was overshadowed by ActiveState's, called ActivePython. That included more Windows-specific packages such as win32com, and the very capable PythonWin IDE from Mark Hammond. That was my go-to Python around 2000-2005.

ActiveState was also notable in the early 2000s for hosting the Python Cookbook, the main repository of useful Python snippets and scripts. This was long before PyPI, StackOverflow and Github.

That and Enthought Canopy, which bundled Spyder, SciPy, NumPy and came a bit later but before Anaconda
My primary exposure to python is when it is failing in some way, often when I wouldn't have even known python would be involved (like trying to install something with npm or apt).

I'm sure this is less of an issue when you work with it every day and are familiar with it, but I always dread seeing python in the requirements for something because it means the odds of it "just working" on a random system are probably not great. Anybody else have this experience?

Yes, but I also had that very same experience with Perl, Ruby, Tcl, and Java during their peak heights of popularity, that they were pervasive and problematic. I feel the landscape of operating systems architectures were much more diverse, and the frequency of software releases and permutations of version combinations in the layers is larger than ever before.
Ruby was more popular, especially when Rails exploded. It was great for scrappy startups, that didn't need Java level quality (and costly time) nor the risks of PHP 4.

The python modules eco-system lead to the stake change. Scikit-learn, Pandas and Numpy made it so useful for visualisation, research, old school modelling ML. Writing and saving files was simple. Making your own module took 2 files with 4 lines of code. How easy.

After establishing use cases in Python 2, which already allowed a lot of C code in practise for speed, Python 3 changed everything with a simpler language that makes it clear what is normal and weird. You might dislike [:-1] at first, but you definitely know it's weird compared to other languages, so you can know what to search for. Not true of abstractions in some other languages like Ruby, for migrating devs.

Then Python caught with Tensorflow/PyTorch a real wave of being the place to go. Kaggle involved 100,000s all coding in Python for data science in the latter half of the 10s. It did this at the same time as the LAMP stack and LAMP pre-installed VPS running cPanel were dying to React/node.js and PaaS approaches on the one hand, and big cloud providers on the other. So suddenly, there was not an easy default 'nix environment with PHP to rely on being available so easily, and adding python to an existing server is super easy (and Flask/Django easy to grep), making adding a backend for ML or whatever, very easy too. Ruby wasn't even on the playing field for many of these use cases.

I think a last small impact was that Ruby was misused where shell scripts could have worked. Many people made Ruby cli tools for their internal team, when shell scripts would have been fine - this frustrated some of their peers away from Ruby. There is no difference from Python here, but I just noticed it more.

I'll just add that python provides a pretty good transition for matlab people doing scientific programming, it keeps all the simplicity for scripting, had a good range of packages, etc, another person brought this up too.

For the generation who used matlab in grad school and then abandoned engineering and science to become software engineers, it provided a good soft landing to transfer skills.

Python is the scriptiest lang that is mostly understandable from other popular C-based langs like C++, Java, JavaScript.

Ruby is too different; too many symbols and idiosyncrasies inherited from Perl, Smalltalk, and created by itself.

That is the root reason why they diverged and Python ended up with the scientific ecosystem.

This is further evidenced by Ruby’s popularity only shooting up with Rails, when 2005 web 2.0 attracted lots of non-CS people to come into the field with no prior C-based experience, so they learned Ruby, html, and css fresh.

Lua is actually a much better embeddable language, but it's not as popular and has its quirks.
Python got Numpy very early on, and other languages never got an equivalent.

And then lots of things were built on top of Numpy - image processing, reading GIS raster data, scipy, pandas, etc etc - and they're all trivial to combine because it's all just Numpy arrays.

Python also had a very friendly and approachable community from the start, and great docs, while Ruby had its documentation in Japanese only for some time.

Django is also top quality, imo. Similar to Rails. But it always seemed Ruby was only good for Rails, whereas Python combines with everything.

So as usual, it's not about the language, it's about the rest.

Rails is far, far more popular than Django.

However, the significance of both declined with the expansion of high-tech options (Spring, Go, Scala, Node.js) and the expansion of low-tech options (Firebase).

So today the popularity of the backend frameworks of each language are less important.

> Rails is far, far more popular than Django.

Maybe it used to, but seems a lot more people at least searches for Django pretty much everywhere except US, Canda and Japan.

https://trends.google.com/trends/explore?date=all&q=%2Fm%2F0...

For people who are wandering like me, the big jump in Django searches was the release of Django Unchained by Quentin Tarantino on Dec 25, 2012.
(comment deleted)
And Django was far from the only Python web framework at the time Ruby on Rails became popular. Django gained popularity largely because it was seen as a Python equivalent to Rails.

Before then Zope (on which the popular Plone CMS was built) was probably the most widely used web framework in Python. But there were many, many others too.

I would dispute that. I always felt Rails was used by a very communicative subset of web developers while the Django users just contracted, delivered, got paid and moved on to the next project without any hassle.
I can confirm. A lot of Django apps out there. People don't make a big scene about it, and it quietly powers a lot of websites. I think one of the powers it has that no one talks about is that you can do microservices within a monolith.
I would like to hear more about this paradigm if you have a minute.
In your wsgi.py file, you specify which settings module to use when loading your WSGI application with, e.g., gunicorn. In your settings.py file, you can specify what your root url config is, e.g. a urls.py file which recursively defines all routes in you application. But nothing is stopping you from having n different settings files, e.g. settings/service1.py with n different urls.py files and loading them in n different wsgi.py files and serving them with n different gunicorn deployments.

You can also do things like adjust the settings defined in your settings.py file to use a different url conf programatically based on environment variables. It is just python, after all.

I first encountered Python around 2000. At the time Perl was more popular in the circles I frequented, and TCL probably about as popular as Python (eggdrop[1] notwitstanding), but Python was growing steadily. I encountered Ruby in the late '00s (as others have noted it made its english-language debut almost a decade after Python started) and Lua was another contender during this time.

My memory is that, at least outside of the web/RoR world, Ruby at no point as popular in the US as Python. Lets take, say 2005 as a point that Ruby was really gaining popularity due to Rails: at this point I was already seeing internal tools that previously would have been written in Perl being written in Python.

Python just seems to have maintained a certain momentum, and I'm not sure why, but if I had to guess:

1. The syntax is almost a dead-ringer for pseudo code. The first time I encountered Python, I fixed a bug in an open-source project having never seen Python before. I recall two different CS programs switched to Python from Scheme for exactly this reason.

2. It was designed to glue C together. Other languages were too (TCL and Lua; Perl primarily interfaced with the outside world in the same way shell does, with pipes).

3. A kitchen-sink approach to the standard library helped it a lot for the first 20 years of its existence. CPAN was sui-generis at the time for installing libraries, so the more you could do without relying on 3rd-party libraries, better off you were.

1: https://en.wikipedia.org/wiki/Eggdrop

I think it upset the Perl hegemony in part because of the enterprise infatuation with object orientation. Perl got a lot of flak from the Java/XML crowd (“Perl’s not a real language—it’s not object oriented!”).

You could kind of write Java in Python, and thus a certain kind of enterprise techie couldn’t dismiss Python as “just” a scripting language.

And of cause the fact that the Perl community relished in inventing new and exiting shorthand tricks that allowed perl script to be essentially write only unless you stuck to an style-guide that had not been codified.

Perl like VisualBasic had a well deserved reputation for facilitating atrocious hard to debug code, and it was this reputation more then the lack of OO/XML support that led both of those to fade back into the realm of forgotten memory and business critical enterprise applications that nobody dares to touch.

The word "enterprise" kind of reminded me of one possible significant reason for python's huge adoption rate after the second part of the 2000s. Google started using it for a lot of things at some point and was advertising a ton of python jobs. That was both a shining endorsement and a possible way into the company.
I actually think Google picked the winner by deciding to use Python, especially for TensorFlow, right at the time when deep learning really started taking off, and also at a time when they were seen as the leader in engineering best practices that other companies wanted to emulate.
Google followed the writing on the wall, nothing else.

Google was known as one of the most academic engineering companies, in the 00-ies.

In my experience, Perl got a lot of flak for being "write only", I don't really remember anybody complaining it wasn't "object oriented".

Every Perl code base I've seen, or inherited, has been a mess. My favourite was a bunch of utilities all written by the same person who never did anything the same way twice. Each utility was like an entry in an obfuscated 'C' contest.

I used Perl to build my first web application at LONG time ago. That project is included in the list of Perl code bases I've seen that were a mess :-)

There was definitely a group of people who thought "object oriented" was the One True Way and any languages that don't support it are "toys." I'm not sure I ever heard their ire directed at Perl specifically, but I recall the sentiment existing.
Oh definitely the attitude exists. I just never saw it directed at Perl. Maybe since, in my experience, Perl has mostly be used as a system language and not a application development language.
How the pendulum has swung!

Rust doesn't even sport 'Class'

I (rather to the displeasure of many people) refer to that kind of OOP Python as "Java fanfic"...
That would be similar to saying C isn't a real language while ignoring the existence of C++. Perl 4 wasn't OO, but Perl 5 enthusiastically embraced OO. The first release of Perl 5 was in 1994, whereas Java 1.0 was 1996.

It did take a while for the wider Perl community to embrace OO, though. There were a lot of Perl programmers who weren't into lofty paradigms. Plenty of Perl programmers weren't fully sold on the idea of breaking your program into functions.

Before Python got popular, Perl was the most similar popular language. Once I encountered Python, I felt, this is Perl, but done right.
+100

I loved Perl, but it had a culture of doing things in N different ways, too many shortcuts, and you ended up with incredibly tiny scripts which were unreadable -- even to the author -- a month later. This wasnt practical for business use in the face of more consistent code from Python

That was my experience. I like Perl. I'm comfortable with Perl. And after about a day of Python, I never wrote another line of new Perl code.

There were so many "it can't possibly be that easy, but it is!" moments.

Let's write a function to add five to a number:

  def add_five(num):
      return num + 5
OK. So, can I pass that function as an argument to another function?

  def call(func, value):
      return func(value)

  call(add_five, 10)
  => 15
What? That worked?! And there was zero additional syntax, you just... do it?

After a seemingly endless list of happy discoveries like that, I seriously rethought my idea of what programming languages could be, and ought to be.

> you just... do it?

A few years from now, when researchers look at mental workload when writing/reading software, we will have the data to prove that Guido was a Neuroergonomics savant.

That sounds trivial? I mean, you can do that in C, what’s surprising about it?

I have never found Python as nice to use as you seem to have, but Ruby always fit like a glove. I’ve written Python since 1999 and I still would rather use almost anything else. It’s so labored to do anything complex. You can build worlds in Ruby in the time it takes you to align indentation properly for a single class in Python.

> That sounds trivial? I mean, you can do that in C, what’s surprising about it?

Here's the C version of it:

  #include <stdio.h>
  
  int addFive(int num) {
      return num + 5;
  }
  
  int call(int(*func)(int), int value) {
      return func(value);
  }
  
  int main() {
      printf("%d\n", call(addFive, 10));
      return 0;
  }
It's still manageable, but not nearly so simple.

Even Perl doesn't let you escape having to consider pointers and references:

  sub addFive {
      return shift() + 5;
  }
  
  sub call {
      my($func, $value) = @_;
      return $func->($value);
  }
  
  print(call(\&addFive, 10));
Why do I have to remember to write `\&addFive` in Perl, when Python doesn't require it? Why do I have to write `$func->($value)` instead of the normal `func($value)` in this case? Why do I have to write `$value` in the first place? That's rhetorical: I know the answers. Still, this was the kind of thing that instantly won me over from Perl to Python. It's not that I could somehow write things in Python that were unwriteable in Perl (or C, or assembler, or ...), but that Python let me concentrate on what I was trying to say instead of how to say it.

In fairness, the equivalent Python code with optional typing is also more verbose than my original, minus the pointer stuff:

  from collections.abc import Callable
  
  def add_five(num: int) -> int:
      return num + 5
  
  def call(func: Callable[[int], int], value: int) -> int:
      return func(value)
  
  print(call(add_five, 10))
The key word there being "optional". Python lets you add that if you want to, but you don't have to. And note that the underlying syntax is identical if you delete the annotations. If you opt in to using them, you don't have to alter the code you're annotating.
You don't have to shift() or unroll @ any longer in recent Perls.

  int call(int(*func)(int), int value) {
      return func(value);
  }
At least in gcc, you don't need to think about pointers. Just use the function signature:

  int call(int func(int), int value) {
      return func(value);
  }
I don't know if this is an extension or what, but it's something I "just tried" on a hunch with no guide in 2009 and it worked.
Python didn't corner the market there:

  (define (add-five num)
      (+ num 5))
  (define (call func value)
      (func value))
  (call add-five 10)
Admittedly, this was one-of-many examples.

I do wonder how much would be different today if not for the Monty Python gags in the documents.

Sigh. I know. We are truly walking in the darkness.

When I’m appointed Lord Emperor, we’ll all upgrade back to Lisp.

It did corner the market for "no extra brackets needed just in case people want to treat code as data which most people don't want to".
If that blew you away you really should try Ruby:

    def call(fn, val) = fn.(val)
    call(->(n){ n + 5 }, 10)
It is still hard to understand unless you are familiar with the language. Python got popular because it made it simple.

Ruby on the other hand encouraged cleverness like what you wrote.

I think ruby faded for the same reason perl did. It is cool to write code, but once it's time to maintain it, especially after the rock star who wrote it left, it sucks.

> cleverness like what you wrote.

So we should optimise languages for users who are not prepared to familiarise themselves with the language? How is this more complicated than its commonly-used Javascript equivalent?

    function call(fn, val) { return fn(val) }
    call(n => n + 5, 10)
You see when written in a language in which lambdas are first-class citizens it doesn't look clever at all so maybe Python's sad implementation of lambdas and its anti-fp culture could be at fault?
Excellent point. I moved from Perl 4/5 (writing fairly involved RADIUS code) to Python (doing other stuff, but still intricate) and the fact that I could actually read my code six months later made all the difference.
As someone who began his programming career with Perl I've never understood this idea that Python somehow improved on Perl. For a start Ruby is Perl5's most obvious successor. Perl puts Python's text-handling to shame whilst Python's lambda is nowhere near as expressive as Perl's. Python also goes head-to-head with Perl's fundamental philosophy - TIMTOWTDI. If anything Python is the Anti-Perl.
> The syntax is almost a dead-ringer for pseudo code.

This is the big one. You look at it, and you think you know what it's going to do. The indentation rules also means things look predictable rather than being a mess of brackets.

This was the reason what made me chose python over ruby.

I wanted a language that I would come back to and still understand what I was trying to do. Ruby looked like its spirit animal was perl.

Python lets people who would not otherwise program write programs. Back in the day the same people used excel with macros.
So, it's both an effective entry point for beginners, and powerful enough to be a utility language for experienced programmers.
The other comments answer this well.

But I'll add Ruby on Rails and a lessor extent Ruby was pushed by hipsters hard and people who didn't program but were internet explorers.

Python just was. You'd never have not considered it a language.

I always thought having Python 2 and 3 held it back a decade. The fact it won despite that means to me it was never a contest.

Yes, an aspect I never thought of ‘till now is that Python is/was cool but never trying particularly hard to look it. Understated British humor may have something to do with that.
In python you just write your business logic. For any "low level"/non-business aspect, you already have great stdlib and rich ecosystem of third party packages.

People care delivering features rather than design and build the best in class architecture.

I wish javascript adopt the same python philosophy, rather the actual "spaghetti mess".

Ruby was never that great of a language. Rails was much better than any alternative, though, and it brought Ruby along with it. Basically every company using Ruby chose it because they wanted to use Rails.

The main thing that has led to the decline of Rails is the rise of no-HTML-just-an-API backends. Your web frontend development stack is more likely nowadays to be, first you pick between React or a similar framework, and then the backend just sends API data and doesn't mess with HTML. This makes for better websites, and it makes joint web and mobile development easier too, because you're going to have to build that API anyway for your mobile app.