A friendly reminder that even a kernel written in C requires some level of assembly. For example, my entry point that sets up a temporary paging structure and jumps to long mode, or my interrupt handlers.
Now, you could compile Python to machine code, but you'd need a Python runtime that supports things like memory allocation and garbage collection.
A purist method would be: Implement a Python runtime in assembly, and run Python in your kernel. (In my opinion, writing a garbage collector in pure assembly would be super difficult.)
A non purist method would be: Start with a unikernel such as
#include <os> or
Unikraft, where the entire OS is treated like one large C++ application. Then
embed a Python interpreter into your OS.
If I were to undertake this, I'd treat the unikernel + Python interpreter as a "micro-kernel". Offer some basic support such as threading, a mechanism for sending messages between Python running programs, and exposing some way of interfacing with io ports and memory mapped hardware in Python. Then implement all of your programs and microkernel services (the window manager, the file system, the hard disk driver, etc.) in Python.