What The Heck Is The Difference Between A Python Interpreter and Python Compiler?

Holy moly this is a loaded (no pun intended) question. So let’s start by making this as simple as possible by understanding how computers work in general.

I bought a brand new MacBook Air that came with an M1 core processor and the job of a processor is to execute machine code (binary code in 0s and 1s). A Mac M1 core processor has a different instruction set architecture (ISA) than an Intel core processor. In simplistic terms, computers consist of processor and memory with an operating system that loads the binary code into memory. The purpose of memory is two-fold: to store instructions (in processor specific ISAs) and to store data.

When I’m doing a simple function on my MacBook, the simple math calculation of one plus one is stored in machine code in data with instructions from the ISA on how to execute the math calculation in the M1 core processor and store the result back into memory. Let’s take this one step further. In languages like C and C++, the source code of my function is stored on my hard drive and translated through a compiler that reads my source code and translates it via the C or C++ compiler into byte code with instructions from the ISA on how to execute it.

So far so good? Let’s go one step further. In Python when we execute the code in our Terminal $$ python3 hello.py, remember that there are two parts to this command. The first part is python3 and this code starts the python interpreter. In other words, python3 is the program C-Python3 that you are actually running. By the way, in this discussion we’re assuming we’re using C-Python3 which is what you would have downloaded from python.org. To understand this more easily, the key concept is to grasp that a python interpreter consists of two parts in memory: the python virtual machine (PVM) and the python compiler. The second part of what we typed into the Terminal is hello.py which is the source code, and it’s important to understand that is not the same as the python interpreter.

The hello.py source code is print('hello world) and it’s stored on my local hard drive on my MacBook. Well, at least until I git push it also to the git cloud server but that’s besides the point. So here is what happens. When we type $$ python3 hello.py, we start the python interpreter and pass the hello.py source code as an argument into the python interpreter in memory.

And the Python interpreter is written in C and has code like  _PyEval_EvalFrameDefault,  PyInterpreterState and CALL_FUNCTION. It has data structures with a link list that links to itself. Any-who, hello.py source code as an argument in the python interpreter gets it’s instructions from ISAs in memory and now the python compiler (which is one of the two parts of the python interpreter) does what all compilers do. All compilers translate source code into byte code, but it’s important to note that byte code is not the same as machine code.

So let’s summarize real quick cos this got computer sciency real quick. The python interpreter sits in memory and consists of the python virtual machine and the python compiler. The byte code which is the third part now in memory but outside of the python interpreter. My MacBook M1 core processor cannot understand byte code (which is kind of confusing because byte code is binary in 0s and 1s BUT is not machine code). So who on earth processes the source code?!! The byte code is processed by the python virtual machine (PVM) which is essentially doing the same job like my M1 core processor. The PVM reads the instructions from the byte code and executes.

So now with all this context, let’s answer the question that I posed in this blog post. The python compiler translates your source code into byte code. The python interpreter consists of two components which includes the python compiler and also includes the python virtual machine that processes instructions from the python compiler’s byte code into execution.