# How Python Works Internally: From Source Code to Bytecode and the Python Virtual Machine

# How Python Works Internally

## Introduction

Python is one of the world's most popular programming languages because of its simplicity, readability, and versatility. But have you ever wondered what happens behind the scenes when you run a Python program?

Although Python is often called an **interpreted language**, the execution process is more interesting than simply reading and executing code line by line.

In this article, we'll explore how Python executes your program—from writing a `.py` file to generating **bytecode** and finally executing it using the **Python Virtual Machine (PVM)**.

---

## Why Understanding Python Internals Matters

Understanding Python's internal working helps you:

- Write better and more efficient Python code.
- Understand why Python is platform-independent.
- Debug performance issues more effectively.
- Prepare for technical interviews.
- Gain a deeper understanding of programming language design.

---

## The Python Execution Process

The execution flow of a Python program looks like this:

```text
hello_python.py
       │
       ▼
Python Compiler
       │
       ▼
Bytecode (.pyc)
       │
       ▼
Python Virtual Machine (PVM)
       │
       ▼
Program Output
```

![Python execution flow: source code to bytecode to PVM to output](https://raw.githubusercontent.com/code-azeemahmad/learn-python/8163475084f16377a0b9a0008c83c01d79e0d6cb/chai-aur-python/basics/python-internal-working.png)
*Figure: How Python source code is compiled to bytecode and executed by the PVM.*

Let's understand each step in detail.

---

### Step 1 – Writing the Python Source Code

Suppose we create a Python file named:

```python
hello_python.py

print("Hello, World!")
```

This file contains **Python source code**.

Source code is human-readable but cannot be executed directly by the computer.

---

### Step 2 – Compilation into Bytecode

When you run a Python program, Python first **compiles** the source code into **bytecode**.

```text
hello_python.py
        │
        ▼
Bytecode (.pyc)
```

Unlike languages like C or C++, this compilation happens automatically.

You don't have to manually compile your program.

---

## What is Bytecode?

Bytecode is a low-level representation of your Python program.

It is:

- Platform-independent
- Easier for Python to execute
- Faster to load than source code

Bytecode is **not machine code**.

Your CPU cannot understand bytecode directly.

Instead, it must be executed by Python's Virtual Machine.

---

### The .pyc File

Compiled bytecode is stored in files having the `.pyc` extension.

Example:

```text
hello_python.cpython-313.pyc
```

Here,

- **cpython** indicates the Python implementation.
- **313** indicates Python version 3.13.

---

### The `__pycache__` Folder

Python stores compiled bytecode inside a folder named:

```text
__pycache__
```

Example project structure:

```text
project/
├── hello_python.py
└── __pycache__/
      └── hello_python.cpython-313.pyc
```

Python creates this folder automatically.

---

## Why Does Python Create .pyc Files?

Python creates `.pyc` files to improve performance.

Instead of compiling the source code every time, Python can reuse the previously generated bytecode if:

- The source code has not changed.
- The Python version remains the same.

This makes importing modules faster.

---

### When Are .pyc Files Created?

Generally,

- Imported Python modules create `.pyc` files.
- Top-level scripts that you execute directly usually do not rely on cached `.pyc` files in the same way.

Python decides automatically whether creating a `.pyc` file is beneficial.

---

### Step 3 – Python Virtual Machine (PVM)

After compilation, Python sends the bytecode to the **Python Virtual Machine (PVM)**.

```text
Source Code
      │
      ▼
Bytecode
      │
      ▼
Python Virtual Machine
      │
      ▼
Output
```

The PVM reads the bytecode instructions one by one and executes them.

This execution process is what makes Python an interpreted language.

---

## What is the Python Virtual Machine?

The Python Virtual Machine is the runtime engine of Python.

Its responsibilities include:

- Reading bytecode
- Executing instructions
- Managing memory
- Handling exceptions
- Running your Python program

You can think of the PVM as the engine that powers every Python application.

---

## Bytecode vs Machine Code

| Bytecode | Machine Code |
| --- | --- |
| Generated by Python | Generated by compilers like GCC or Clang |
| Platform-independent | Platform-dependent |
| Executed by the Python Virtual Machine | Executed directly by the CPU |
| Not understood by hardware | Directly understood by hardware |

---

## Is Python Really an Interpreted Language?

This is a common interview question.

The answer is:

**Yes, but not entirely.**

Python follows a **two-step execution process**:

1. Source code is compiled into bytecode.
2. The Python Virtual Machine interprets the bytecode.

Therefore, Python is often described as **both compiled and interpreted**.

---

## Different Python Implementations

Python has several implementations.

### 1. CPython

- Official Python implementation.
- Written in C.
- Most widely used implementation.

---

### 2. PyPy

- Uses a **Just-In-Time (JIT)** compiler.
- Usually faster than CPython for long-running programs.

---

### 3. Jython

- Runs on the **Java Virtual Machine (JVM)**.
- Allows Python to interact with Java libraries.

---

### 4. IronPython

- Runs on Microsoft's **.NET Common Language Runtime (CLR)**.

---

### 5. Stackless Python

- Designed for lightweight concurrency.
- Useful for applications requiring many simultaneous tasks.

---

## Complete Execution Flow

```text
          hello_python.py
                 │
                 ▼
      Python Compiler
                 │
                 ▼
        Bytecode (.pyc)
                 │
                 ▼
     Python Virtual Machine
                 │
                 ▼
        Machine Instructions
                 │
                 ▼
              Output
```

---

## Example

Consider the following program:

```python
x = 10
y = 20

print(x + y)
```

Python internally performs the following steps:

1. Reads the source code.
2. Compiles it into bytecode.
3. Stores the bytecode (when appropriate).
4. Sends the bytecode to the Python Virtual Machine.
5. The PVM executes each instruction.
6. Displays:

```text
30
```

---

## Common Misconceptions

### Python executes `.py` files directly.

Not exactly.

Python first converts source code into bytecode.

---

### Bytecode is machine code.

No.

Bytecode is Python-specific and cannot be executed directly by the CPU.

---

### Python always creates `.pyc` files.

Not always.

Python mainly generates cached bytecode for imported modules and when it is useful to do so.

---

## Key Takeaways

- Python programs are written in `.py` files.
- Python automatically compiles source code into bytecode.
- Bytecode is stored as `.pyc` files inside the `__pycache__` directory.
- Bytecode is platform-independent.
- The Python Virtual Machine executes bytecode.
- Bytecode is **not** machine code.
- CPython is the official Python implementation.

---

## Conclusion

Although Python appears simple from the outside, several steps occur before your program runs.

Python first compiles your source code into platform-independent bytecode. This bytecode is cached inside the `__pycache__` directory and then executed by the Python Virtual Machine (PVM). Understanding this execution process gives you a deeper appreciation of Python's design and helps you become a more knowledgeable Python developer.

Whether you're preparing for interviews, learning Python, or simply curious about programming language internals, knowing how Python works behind the scenes is an important step toward mastering the language.

---

## Thank You for Reading!

If you found this article helpful, consider following my blog for more tutorials on:

- Python
- C++
- Data Structures & Algorithms
- MERN Stack
- Next.js
- Artificial Intelligence
- Software Engineering

Happy Coding!
