The best practice, which prevents this issue, is to use envs, (as well as pinning your dependencies for any given project in a committable artifact).
(Seems like a lot of people are using system Python, which isn't really recommended.)
The whole idea that you need a multitude of environments to support applications written in the same interpreted language is where it breaks, that should not have been necessary if backwards compatibility had not been an issue.
I really like the language, but all the tooling is seriously broken.
Fwiw what I've settled on that seems the most stable is to use pyenv as the "outer layer", as it shims the python interpreter along with any venvs so you don't get conflicts / heisen-incompatibility. Lets you use anaconda envs as children as well. The real trick, I think, is to pick one system as the canonical master env controller and don't deviate.
The code typesetting is for the humans not the machines.
That is a lot worse than formatting squabbles, especially for a glue language where you are expected to be able to copy snippets for short scripts all the time.
The libraries are very powerful, but a lot of them are hacks. Numpy and Pandas totally rely on magic and overloading the array indexing operator. You can't express a problem the natural way or it will be slow, you have to think the numpy way. I find it especially confusing if you create expressions with numpy arrays. Am I operating on them element wise, or creating a "cross product", or am I creating some kind of magic indexing object? Matplotlib is also annoying, there are so many ways to do things and half of it is object oriented, while half of it uses global state.
One thing I like about Python are the web frameworks (Django, Flask). Async is also good, although it took almost 10 years for vanilla Python to catch up with what Twisted already had.
About code breaking I also have the opposite experience. I wrote a little Gtk app in the late 2000s and it worked with little or no changes for many Python and Gtk versions, thanks to the dynamism of Python. That would be completely impossible with a compiled language.
The language is 100% capable. Matplotlib's API is horrible and confusing because one of their design goals was/is to be similar to matlab (that's where the "mat" in it's name comes from) to allow people who are comfortable with matlab to switch more easily.
Matlab's plotting facilities are a mess of global state, so matplotlib has copied it.
> An 'elegant' language would provide a way to do so without all of these leaky abstractions.
It would have to do something else, first: Exist.
In 10+ years of programming, I've yet to ever see a implementation of a complex abstraction that was comprehensive and complete enough that I didn't find a corner case requiring me to reach through it and deal with platform specific something-or-other.
I think I like Python, because coming from C, a lot of things that are tedious there are effortless in Python (Strings! Lists and dicts, libraries, and so on.)
That's why each and every number crunching problem will eventually make use of the various escape hatches to call libraries written in a language that is performant.
As for strings: BASIC also had strings. That doesn't mean that having strings (or even dicts) is what makes a language elegant.
The problem really is that there are only so many sweet spots for programming languages and usually those come with limitations with respect to the domain you want to use them for. Pick any two: expressive, fast, easy to use.
But it would be a mistake to consider Python anything but luxury glue no matter how much you've used it for production code, it isn't and never will be a bullet proof language, there are just too many ways in which the runtime can surprise you and the long term maintainability of any Python codebase is always going to be questionable, in part because you will most likely have dependencies on stuff that will silently disappear or change out from under you while you're not watching.
I've been writing Python code pretty much since it was first released and there isn't a single piece of code that I ever put together that worked longer than a few years out of the box without some breaking change. This as opposed to just about every other language that I've used, which I find very frustrating because Python could be just about perfect. And I'm still sore about significant whitespace ;)