Mechanically, I believe the main difference is that NPM corresponds to PyPi + pip; it's both registry and repository. PyPi is Python's official package repository and pip's default source, but it's not pip's only possible source. If someone pulls code off PyPi, pip can still link to it elsewhere.
When the left-pad debacle [1] broke major packages, the triggering event was that NPM-the-registry took a module name away from a developer and gave it to a company (which held it as a trademark). He got mad and took all his code off NPM-the-repository, including left-pad. To settle the chaos, NPM had to restore the deleted code against the developer's wishes - even though his code was still available on GitHub.
Realistically, though, that would still cause some chaos and it doesn't seem to be the key difference. The more important differences are legal and practical.
npm, inc. is a private company, while PyPi (via Warehouse) and pip are both open-source and donation funded. Even if npm doesn't get up to anything malicious, they depend on keeping their registry and repository unified, and they're more likely to attract and buckle under trademark suits than PyPi.
Even more importantly, npm modules are tiny. PyPi packages and Ruby gems may be single-purpose, but they usually do something which isn't completely trivial, and common functions like math libraries are built into larger packages. npm left-pad was 17 lines of string-padding code that almost anyone could write. Other modules are even sillier; isArray has millions of weekly downloads for what is effectively a single line of code. Blank npm templates have tens of thousands of files loaded even before you start coding.[2] So fundamentally, a big part of the issue is just that node projects tend to pull in 10x or 100x more dependencies than most other projects.
I think the problem is that NodeJS has a weird culture where a separate package is created for every little thing, then tons of other packages start depending on it.
I don't live in NodeJS world but even I heard about package Left-Pad, that all it does is padding string from the left side. The author decided to pull it out from the repo rendering tons of other packages nonoperational[1].
The number of packages you need to audit for what would otherwise seem to be a trivial feature is exponentially larger in JS world than in Python. A good example of that is the left-pad debacle, wherein a package that left-pads a string was taken down, causing other packages - notably React - to fail to be installed because of either direct or transitive dependencies.
In the Python world, it is indeed likely that unpublishing requests will cause issues, but the number of dependencies you'd need to audit/vendor is _much_ smaller for a typical python app than it is for a typical nodejs app, so your "attack surface" is also comparatively much smaller.
Python has a standard library that is not horribly anemic, and, as far as I know, there isn't anywhere near the same propensity to atomize packages. NPM is infamous for having stupidly small packages like isEven or leftPad, and monstrous transitive dependency trees.
A large Python package might have fewer than 10 dependencies, while a typical JS package easily has hundreds if not thousands of dependencies. Its much easier to manage your dependencies when you can count them on your fingers.
Difference in approach to libraries and the standard library.
NPM/Node is very much a "we only provide the bare minimum for a language, everything else must be implemented on your own." The JavaScript stdlib is very small (not that weird when you consider it's originally a language to do stuff with in your browser).
The result is that a lot of "simple" functionality that most languages would put in the stdlib (left-pad is the most infamous example) has to be reimplemented by library developers. Now because programmers are for the most part not interested in copying the same code over and over, this means that these simple functionalities end up on the npm, which are then used in somewhat bigger libraries, right up until you essentially create a massive dependency chain for each major library, since the dependencies for that library rely on other dependencies and so on so forth.
This sounds interesting in theory, but in reality this almost always means that if one thing in this chain breaks (for example a "simple" library introduces a breaking change but doesn't properly adhere semantic, since nobody enforces semantic on the npm although it's recommended), essentially the entire chain is broken and the top level library stops functioning as well.
And then you end up with packages such as left-pad, which provide simple functionality that is almost universally needed for almost all major libraries. Now the last thing you want to have happen here is that the maintainer either removes or breaks the package, since this essentially results into a dependency hell cascade as suddenly several millions of packages are broken.
Python on the other hand has probably one of the biggest standard libraries I've seen in a programming language, and the difference is outstanding. Most PyPi libraries are moreso focused on adding specialized features or simplifying otherwise lower level libraries into more higher level ones (ie. requests is really nothing other than a really good wrapper around urllib). There's very few "simple functionality" libraries for PyPi, since most of this functionality is already in the standard library. Usually if a library that is "simple functionality" isn't in the standard library, it's because it changes too often (standard library is mainly for unchanging code. eg, requests) or is still somewhat specialized (ie. sqlalchemy or a couple of validator packages I use).
There's pro's to Nodes approach (ie. you're generally not locked down to a single approach), but generally Pythons approach on library management is better in my opinion.
When the left-pad debacle [1] broke major packages, the triggering event was that NPM-the-registry took a module name away from a developer and gave it to a company (which held it as a trademark). He got mad and took all his code off NPM-the-repository, including left-pad. To settle the chaos, NPM had to restore the deleted code against the developer's wishes - even though his code was still available on GitHub.
Realistically, though, that would still cause some chaos and it doesn't seem to be the key difference. The more important differences are legal and practical.
npm, inc. is a private company, while PyPi (via Warehouse) and pip are both open-source and donation funded. Even if npm doesn't get up to anything malicious, they depend on keeping their registry and repository unified, and they're more likely to attract and buckle under trademark suits than PyPi.
Even more importantly, npm modules are tiny. PyPi packages and Ruby gems may be single-purpose, but they usually do something which isn't completely trivial, and common functions like math libraries are built into larger packages. npm left-pad was 17 lines of string-padding code that almost anyone could write. Other modules are even sillier; isArray has millions of weekly downloads for what is effectively a single line of code. Blank npm templates have tens of thousands of files loaded even before you start coding.[2] So fundamentally, a big part of the issue is just that node projects tend to pull in 10x or 100x more dependencies than most other projects.
[1] https://www.theregister.co.uk/2016/03/23/npm_left_pad_chaos/
[2] https://www.davidhaney.io/npm-left-pad-have-we-forgotten-how...