The Dual Nature of Python: Compiled and Interpreted Explained

Understanding Compilation and Interpretation

Generally a computer program is written using a high-level programming language (C, C++, Java, Python) which we humans can understand better. On the other hand machines understand low-level language (binary). To mitigate this communication gap between humans and machines, a translator was needed. A translator is a piece of software which converts a high-level language to the binary language which machines can understand. There are two types of translator: Compiler and Interpreter.

Compiler : A compiler is a software tool that translates source code into machine-readable binary code in a single step, producing an executable file. This executable can be run directly on a machine without the need for the original source code or recompilation. The file extension for executables depends on the operating system: .exe for Windows and .app for macOS. Compiled executables are specific to the operating system they were created on but can be run on any machine of the same type. This makes the code non-portable but highly secure as we are just sharing the executable and not the actual code. Examples of compiled languages include C, C++, etc.

Interpreter : An interpreter is a software program that translates source code to machine code line by line at runtime, without generating an executable file. To run the same code on another machine, the source code must be sent to that machine, which must also have the interpreter installed. This makes the code portable to run on any machine. Examples of interpreted languages include JavaScript, Ruby, PHP, etc.

Just-In-Time (JIT) compiler

A Just-In-Time (JIT) compiler is a type of compiler that combines features of both interpreters and traditional compilers. It translates code into machine code at runtime, rather than before execution, like traditional compilers. This means that JIT compilers compile code on-the-fly as it is needed, improving performance by optimising code execution dynamically.

When source code is provided to a JIT compiler, it generates bytecode (intermediate code) instead of an executable. This bytecode can be run on any machine with an interpreter installed. The interpreter executes the bytecode and generates machine code on the fly. This allows bytecode to be run on any machine without needing the original source code, as long as the machine has the appropriate interpreter installed.

Python's Code Execution

The Python interpreter is responsible for executing Python programs. The process of executing Python code involves several stages, each handled by different components of the Python interpreter. These components include the lexer, parser, compiler, PVM (Python virtual machine), memory manager, garbage collector, standard library, built-in functions, and interactive mode.

Now the question arises, is python compiled or interpreted ? Python is both compiled and interpreted language. It’s a hybrid language that uses both compiler and interpreter for its translation. Examples of hybrid languages include Java, Python, C#, Kotlin, etc.

Below are the python execution steps :

  1. Source code is provided to the compiler. Extension of source code is .py

  2. Compiler in turn generates bytecode. Extension of bytecode is .pyc

  3. Bytecode is provided to python virtual machine, this PVM can be installed on any machine. It can be Windows, Mac or Linux.

  4. PVM generates machine code on the fly.

Hence we saw that python involves both compilation and interpretation in the code execution process. It provides code privacy from compilation and portability from interpretation.

How to see the bytecode ?

In reality when you run the code, you will never see the bytecode. In order to see the bytecode you just need to compile the code. Simply running Python code involves both compiling and interpreting it. To compile without executing, follow specific steps.

  1. Consider an existing python file or create a new one in your machine.

  2. Import module named py_compile and use it to compile the python file.

  3.     import py_compile
        py_compile.compile(‘filename.py’)
    
  4. The above code will generate a folder named __pycache__ where filename.py file resides and within that folder you will find the bytecode file named as filename.cpython-310.pyc

  5. Here 310 is the python version you have installed on your machine. There are different versions of Python, including Python 2 and Python 3, and different implementations of the Python interpreter, such as CPython, Jython, IronPython, and PyPy.

Summary of the article :

Computer programs written in high-level languages (e.g., C, Java, Python) need translators to convert them into machine-readable binary code. This translation can be done by compilers or interpreters. Compilers translate the entire code at once into an executable, whereas interpreters convert code line-by-line during runtime. JIT compilers blend both methods, translating code into bytecode at runtime for dynamic optimisation. Python uses a blend of compilation and interpretation, converting source code (.py) to bytecode (.pyc) and then executing it via the Python Virtual Machine (PVM). To view Python bytecode, use the py_compile module.

2
Subscribe to my newsletter

Read articles from Ashwini Jangetol directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ashwini Jangetol
Ashwini Jangetol