Python was meeting needs well enough to be one of, if not the single, most popular language for a considerable time and continuing to expand and become dominant in new application domains while languages that focussed more heavily on performance rose and fell.
And it's got commercial interests willing to throw money at performance now because of that.
Seems like the Python community, whether as top-down strategy or emergent aggregate of grassroots decisions made the right choices here.
Python had strengths that drove it's adoption, namely that it introduced new ideas about a language's accessibility and readability. I'm not sure it was ever really meeting the needs of application developers. People have been upset about Python performance and how painful it is to write concurrent code for a long time. The innovations in accessibility and readability have been recognized as valuable - and adopted by other languages (Go comes to mind). More recently, it seems like Python is playing catch-up, bringing in innovations from other languages that have become the norm, such as asyncio, typing, even match statements.
Languages don't succeed on their technical merit. They succeed by being good enough to gain traction, after which it is more about market forces. People choose Python for it's great ecosystem and the availability of developers, and they accept the price they pay in performance. But that doesn't imply that performance wasn't an issue in the past, or that Python couldn't have been even more successful if it had been more performant.
And to be clear, I use Python every day, and I deeply appreciate the work that's been put into 3.10 and 3.11, as well as the decades prior. I'm not interested in prosecuting the decisions about priorities that were made in the past. But I do think there are lessons to be learned there.
In my experience it's far more common for "optimizations" to be technical debt than the absence of them.
> only ever think about performance in retrospect
From the extra context it pretty much does mean that. "but only after that code has been identified" - 99.999% of programmers who think they can identify performance bottlenecks other than in retrospect are wrong, IME.
Well it's entirely possible that Knuth and I disagree here, but if you architect an application without thinking about performance, you're likely going to make regrettable decisions that you won't be able to reverse.
It is not possible to predict bottlenecks in computation, no. But the implications of putting global state behind a mutex in a concurrent application should be clear to the programmer, and they should think seriously before making a choice like that. If you think of a different way to do that while the code is still being written, you'll avoid trapping yourself in an irreversible decision.