Don't Just Code, Understand the Game: Python Inner Working - Explored

Darshan JoshiDarshan Joshi
11 min read

Namaste and hello everyone! Ever hit that 'Run' button on your Python script – wham! – and then just kinda hoped for the best? It's a bit like watching a six sail over the boundary in the IPL, right? That amazing result, but have you ever stopped to think about all the little things that had to happen just right to get there?

As folks, we spend a lot of time writing the code, which is kind of like a cricket team planning their every move, their batting order, their bowling strategy. But honestly, understanding the engine that actually makes our code work? That can be a real game-changer. It can give you those deeper insights, help you level up your skills, and just make you a more confident developer.

Now, if you've ever been on the hunt for someone who can explain the tricky bits of tech without making your eyes glaze over, you might've stumbled upon Hitesh Choudhary. That guy has a knack for taking these complex ideas and just… making them click. He breaks things down in a way that's not only clear but actually kind of fun! I was watching one of his videos recently, and it totally got my gears turning. It's actually what inspired me to write this for you all.

So, buckle up! We're about to take a peek under the hood and explore the inner workings of Python together. And because, as some of you might know (or maybe you're finding out now!), I'm a massive cricket fanatic, we're definitely going to be throwing in some cricket analogies along the way. Hopefully, it'll make everything feel a little more familiar and, dare I say, a bit more desi! πŸ˜‰ Let's get started!

The First Innings: Compilation to Bytecode

Suppose we are writing one simple python script for defining the function which will take integer value as its input parameter and will print the square value of the given input parameter.

def square_values(x):
    print(x*x) 

square_values(45)

You can see in the below screenshot, I have created python script file on my local machine using VS Code.

Well we will save the file and execute the script using the command which will execute the python file.

python source.py

Executing the file will not give us any surprises! it will return the result which it is intended to do, which you can witness in the below snapshot.

Well, it seems simple enough right? but we will see the inner workings of python which will satisfy the query of how the python is executed in the backend of your system.

Alright, so picture this: your Python script, the code you actually wrote, doesn't just stroll up to your computer's brain – the CPU – and start having a conversation. It's not like the CPU is a bowler just waiting for the first ball. Instead, there's this initial step that Python takes, kind of like preparing the pitch and getting the batsman ready before the actual innings even begins.

What happens is, Python first goes through your code and "compiles" it. Now, "compile" might sound all techy and intimidating, but think of it more like translating. Your human-readable code, the stuff with all the ifs and fors, gets turned into something a bit more… well, digestible for the computer later on. This intermediate form is called bytecode. It's like getting the bat ready, making sure the grip is right and the stance is solid, before you actually face the bowler. Bytecode is that "ready bat" – it's not the final swing, but it's the prepared form that's about to be used.

Meet the Captain : The Python Virtual Machine (PVM)

Okay, so you've got this prepared "bat" – the bytecode – all ready to go. Now, who's the one who actually steps onto the pitch and plays the shots? That's where the Python Virtual Machine, or PVM for short, comes into the picture. Think of the PVM like the captain of the team who's out there in the middle, calling the shots (pun intended!).

It takes those bytecode instructions, one after the other, and basically tells the computer what to do. It's like the captain looking at the field, understanding the situation, and then instructing the batsman on which shot to play. The PVM reads each line of bytecode and executes it step by step.

And you know what? This is exactly why we often hear people say that Python is an interpreted language. Because it's not directly translated into the computer's low-level language all at once, before running. Instead, the PVM acts like an interpreter, reading and executing the bytecode line by line, in real-time, as the program runs. It's like having a captain who's constantly giving instructions and making decisions as the innings progresses.

This "captain" setup is what allows your Python code to run seamlessly across various operating systems – be it the "Wankhede Stadium" (Windows), "Arun Jaitley Stadium" (Linux), or "MA Chidambaram Stadium" (macOS).

Strategic Time-Outs: .pyc Files and the __pycache__ Folder

Alright, let's talk about those weird .pyc files and that sneaky __pycache__ folder that sometimes pops up in your project. You ever see them and wonder, "What's all this extra stuff?" Well, trust me, it's not just digital junk piling up!

Think about it this way: when your Python script needs to use other bits of code – we call them modules or packages – it's like bringing in some star players for a really important partnership in a cricket match. Now, imagine if every single time you needed those star players, you had to go through the whole process of getting them ready, warming them up, explaining the strategy from scratch. That would waste a lot of time and energy, right?

That's where those .pyc files and the __pycache__ folder come in. When your Python script imports these modules or packages, Python is smart. It takes those "prepared bats" – remember, that's the bytecode we talked about earlier – for those imported bits and saves them into these .pyc files, tucked neatly inside that __pycache__ folder. It's like having those star players already warmed up and ready to step onto the field.

Let us rewrite our exemplary code in such way that we can understand the above context in better way. We will create another python script with whatever filename you like! let me name it destination.py. In the latest file we will import the function which we had created earlier and will call the function while executing the script and then result of execution will lead us to motive of understanding.

from source import square_values #importing the function from other file

square_values(105)

We will execute the destination.py script file and results are visible as per below:

It returned the results which were expected, but let us now see in the folder where we have created the script files which are having some system generated changes which are different than earlier script execution.

The Python interpreter takes your .py file and translates it into a .pyc (compiled Python) format in memory (and sometimes saved to disk). Bytecode is faster in terms of execution than the scripting code itself. It is also called as frozen binaries.

You can see that it has created a folder __pycache__ which contains the bytecode generated while executing the destination.py file as it is caching the source.py file and the function for using it multiple times, anywhere. It will not regenerate / update new bytecode every time unless and until there is change in the source.py file itself. bytecode name suggests that it is compiled python and using version of python for execution which is 3.13. Kindly take a note that this works for only imported files. It is not for top level files for your project / folder structure.

Different Leagues, Different Styles: Python Implementations

Okay, so we've talked about how Python takes your code and gets it ready to run. But here's a slightly mind-bending thing: the "Python" that does all this isn't exactly the same everywhere. Think of it like cricket league . The IPL is huge, right? It's probably what comes to your mind first when you think of league cricket. That's kind of like CPython – it's the standard, the one most of us use day in and day out. It's written in a language called C, and it's the OG, the one everyone expects.

But just like the IPL isn't the only cricket league out there, right? You've got the Big Bash in Australia, the CPL in the Caribbean, and tons of other leagues, each with its own flavor and maybe slightly different rules or focus. Well, it's similar with Python. There are other ways to actually run Python code, different "engines" under the hood.

For instance, there's this thing called Jython. Imagine a player who's really good at playing both regular cricket and this other game that's played on a Java-based field. That's Jython. It lets your Python code run on something called the Java Virtual Machine (JVM). Why would you want to do that? Well, if your whole project or company uses a lot of Java stuff, Jython lets your Python code talk to all that Java code super easily. It's like having a player who can seamlessly fit into a team that's mostly made up of Java players.

Then you've got IronPython. Think of this as the Python that's really good buddies with Microsoft stuff. It runs on something called the .NET framework, which is a big deal in the Windows world. So, if you're building applications or doing automation on Windows and using languages like C# (which is part of .NET), IronPython lets your Python code play nicely with all of that. It's like having a star player who's a local hero on their home ground.

And hey, there are even more out there, like PyPy, which is all about making your Python code run faster (think of a player who's just incredibly quick between the wickets and scores runs at lightning speed!), and MicroPython, which is a tiny version of Python that can run on those little computer chips you find in gadgets and robots (like a smaller, more agile version of cricket for smaller teams).

So, the main takeaway is that while most of us are using CPython as our go-to "IPL," it's good to know that there are other "leagues" out there – Jython for Java connections, IronPython for the Microsoft world, and others for different needs. The core Python language stays pretty consistent, but the way it's actually run can have its own quirks and advantages depending on the "league" you're playing in.

The Power Plays: Understanding "Dunders"

Okay, let's chat about those funny-looking things in Python with double underscores on either side, like __init__. You might've seen them and thought, "What's with all the underscores?" Well, they're not just some quirky Python decoration!

Think of them like the "power play" shots in a batsman's arsenal. They're special moves, predefined techniques that have a specific purpose and can really change the game. These "dunder" (short for double underscore) methods, sometimes called "magic methods," give your Python objects some serious superpowers, allowing them to interact with the language in really cool and fundamental ways.

Knowing these "dunder" methods is like understanding all the special shots a batsman has in their bag. It lets you craft Python programs that are not just functional but also really elegant and Pythonic – capable of hitting those metaphorical sixes when you need them most!

From Bytecode to the Boundary: Bytecode vs. Machine Code

Always remember that generated bytecode is not machine code. It is not used for giving direct instruction to hardware.

Alright, so that bytecode we've been talking about? It's not the very last step. Think of it like this: that bytecode is like the really detailed instructions the coach gives to the batsman – "Okay, for this bowler, on this part of the pitch, you're going to step forward, swing like this, and aim for that gap."

Now, the PVM, that Python Virtual Machine we met earlier, is like the player who actually takes those instructions onto the field. It doesn't just read the instructions; it translates them into the actual movements needed to hit the ball. It's the PVM that figures out exactly how to move the bat, how much force to apply, all those tiny little actions that result in the ball going where it needs to go.

And what's the very final step? That's machine code. That's the real language that your computer's hardware, the CPU, actually understands directly. So, the PVM takes those bytecode instructions and breaks them down into this super low-level language – it's like the precise muscle movements of the batsman, the exact way they shift their weight and swing the bat, that ultimately sends the ball soaring over the boundary.

So, when you start to understand how Python "prepares the pitch" (compiles to bytecode), "plays the innings" (the PVM executing), and even strategically "saves energy" (those .pyc files), it really gives you a much better feel for the language. You start to see why things are the way they are, like why those .pyc files exist or why there are different flavors of Python out there. You don't need to become a PVM expert overnight, but just grasping these basic ideas gives you that crucial "umpire's eye view" – a better understanding of the whole game and how your Python code actually gets from the lines you write to the actions your computer performs. It can even help you write better, more efficient code down the line!


Alright folks, that's the innings on how Python runs your code! Hopefully, you now have a slightly less hazy idea of how your beautifully written Python gets turned into something the computer can actually understand, thanks to that bytecode magic and the PVM's steady hand on the tiller. So next time you hit 'Run', you can picture your code getting its bat prepped, the PVM stepping up to the crease, and maybe even those .pyc files chilling in the __pycache__ dugout, ready for their turn. Now go forth and code, and may your programs always execute with the grace of a well-timed six... and without too many unexpected errors! Cheers!

If you want to watch the YT video for aforementioned explained content, you can go to below video

Thanks and Adios!

The accidental techie signs off !!!!!!!!!!

0
Subscribe to my newsletter

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

Written by

Darshan Joshi
Darshan Joshi

A dedicated Computer Engineering graduate from SCET. Throughout my academic journey, I navigated the dynamic landscape of education during the challenging Covid era, which instilled in me resilience and adaptability. My experience in the field of Data Engineering spans across Transact SQL, MS SQL Server, Agile Methodologies, and a foundational understanding of Azure Data Factory and various cloud services. These experiences have not only honed my technical acumen but also reinforced my capacity to thrive in diverse and evolving environments. My current pursuits reflect a keen interest in expanding my knowledge in both DevOps and Cloud Engineering. Alongside these technical endeavors, I'm fervently learning Full Stack Web Development from the ground up, eager to explore the intricate interplay of front-end and back-end systems. Embracing a holistic approach to problem-solving, I'm delving into the intricacies of System Design, striving to develop comprehensive and efficient solutions within the IT industry. Building on approximately 6 months to 1-year of hands-on industry experience, I'm driven to continuously enhance my skill set, contributing meaningfully to the technological landscape. Beyond the realms of technology, I find solace in capturing the ephemeral beauty of sunsets through photography, letting the time freeze those breathtaking moments. Music is my constant companion, offering relaxation and inspiration. As an avid cricket enthusiast, the game brings camaraderie and excitement. I'm always open to connecting with fellow professionals, learning from shared experiences, and contributing to the ever-evolving tech sphere. Let's connect and explore the limitless possibilities together!