I like that magic method names generally all follow the same form so it's obvious that they are magic methods and not intended to be part of the public API. Whether that form uses double underscores or something else doesn't really matter to me as they are not being called directly.
"Magic methods" is just the name people use for these special methods (another is dunder methods). They're "magic" because you do not call them by name, rather they are invoked by the interpreter in specific situations.
Yes, it is magic the same way other magic methods are, that is, because it is syntactically special and callable (and primarily called by) a syntax other than <instance>.<method>(...) or <class>.<method>(instance, ...)
Specifically, in the case of constructors, via <class>(...).
> it's obvious that they are magic methods and not intended to be part of the public API
Is there an alternative API? No. This is public API regardless of anyone's intentions. Though "it's weird" is really not a very strong argument against it.
Public API refers to the user of the class, not the implementer. You never call __init__ directly. __new__ allows modifying object creation itself for the implementer, but the user of the class will never call it.
There are private and public methods. Private methods are only supposed to be called within other methods, as in privately. Public methods are the ones that are normally called through the code, repl, by the user or whatever. You are not supposed to write `myclass.__add__(x)` anywhere except where you define the class itself and its methods.
Internal is more convention as the language doesn't really do anything with it, but it does with munged, and magic methods are specifically for things implemented in the language.
Internal and munged don't exactly map to private and protected, but are kinda similar ish.
Oh right. I am not really into python, had read some doc about naming conventions some poitns.
In any case I actually like how one can use underscores to point on how exposed some method is supposed to be. Makes it simpler to actually know what to skip and what not.
There are several alternative API's. @dataclass is one, Pydantic offers another, there's also attrs, plus less general things like namedtuple.
Admittedly it's obnoxious when you've got habits for one and you're on a team that uses another--totally flies in the face of the zen re: "there should be only one obvious way to do things".
...but that was always a rather ambitious goal anyway. I'm ok navigating the forest of alternative API's if it means not being locked into something that I can only change by choosing an entirely different language. I'm happy that it's very easy to tell when somebody is mucking about with python internals vs when they're mucking about with some library or other.