Control over destructuring isn't entirely new territory for PLs, Scala has Extractor Objects[0], as an example.
I think that it's a bit easy to say "it should just match the type!" when the reality is that even basic classes like list get overwritten in Python. Ultimately many language features have configurable features through dunder methods, and the fact that those get used by other language features is a feature, not a bug IMO.
As usual, don't use libraries that do weird stuff... and every once in a while you'll have the nice DSL that does something useful in this space and it will work well.
The thought experiment about a more restrictive version of this: how does Python tell that an object is a list? If it's through isinstance, then you're hooking into a bunch of tooling that have hooks that can be overwritten. If it's _not_ through isinstance, suddenly you have multiple ways to test if something is a list (which is a problem).
[0]: https://docs.scala-lang.org/tour/extractor-objects.html
> Abstract base classes complement duck-typing by providing a way to define interfaces when other techniques like hasattr() would be clumsy or subtly wrong (for example with magic methods). ABCs introduce virtual subclasses, which are classes that don’t inherit from a class but are still recognized by isinstance() and issubclass().
You simply don't "subclass ABCs" ever (except when defining an ABC); if you do it's no longer a virtual subclass and you're no longer implementing the ABC. As a concrete example, when did you last "subclass" collections.abc.Iterable? You did not, you implemented __iter__.
Abstract Base Classes were an attempt to formalize python's duck typing. Matching things that don't inherit from them is their whole purpose.
All in all, I really don't get the dramatic tone in this article. It turns out that in python (as in most languages that give you access to the internals) if you mess with the internals the results are well messy. But literally nothing in this article suprised me at all.
Perhaps it would have been a bit clearer, and less easy to dismiss as a fuss over nothing, if the author had left the 'not' out of the definition of NotIterable.__subclasshook__(), or defined an IsIterable class with the 'not' in place?
I am not sure if it wouldn't have been better to make the conversion explicit here.
Python isn't even unique in this regard! You can iterate over a string whether you're working in JavaScript, C++, or Go. (And that's not even getting into cases like Haskell where String is merely syntactic sugar for [Char].)
Which he explained in another article that it allows the author of the abstract class to hijack calls to isinstance for any instances created from subclasses.