While I get your point that Python is often not the most appropriate language to write certain parts of an OS, I have to object to the supposed necessity of C. In particular, the bolded claim that an OS not written in C is still going to have C involved.
Such an OS could instead have written its non-native parts using assembly. And while C was intentionally designed to be similar to assembly, it is not synonymous with assembly. OS authors can and do write assembly when even the C language cannot do what they need, and I gave an example of this in my comment.
The primacy of C is not universal, and has a strong dependency on the CPU architecture. Indeed, there’s a history of building machines which are intended for a specific high-level language, with Lisp Machines being one of the most complex – since Lisp still has to be compiled down to some sort of hardware instructions. A modern example would be Java, which defines the programming language as well as the ISA and byte code: embedded Java processors were built, and thus there would have been zero need for C apart from legacy convenience.
Yes, and that’s basically what the CPython interpreter does when you call a Python script. It sometimes even leaves the result laying in your filesystem, with the extension .pyc . This is the byte code (aka machine code) for CPython’s implementation of the Python Virtual Machine (PVM).
Almost. The .pyc file is meant to run with the appropriate PVM, not for x86 or ARM64, for example. But if you did copy that .pyc to another computer that has a CPython PVM, then you can run that byte code and the Python code should work.
To create an actual x86 or ARM64 binary, you might use a Python compiler like cython, which compiles to x86 or ARM64 by first translating to C, and then compiling that. The result is a very inefficient and slow binary, but it is functional. You probably shouldn’t do this though.