Code4IT

Handcrafted articles for .NET enthusiasts, Azure lovers, and Backend developers

Python for .NET devs: Introduction, virtual environments, package management, and execution lifecycle

2026-03-03 Last updated: 2026-03-03
12 min read Python

Are you a .NET developer looking to learn Python? Me too! In this article we draw parallels between Python and .NET basic concepts, exploring virtual environments, package management with pip, and the execution lifecycle.

Table of Contents

Just a second! 🫷
If you are here, it means that you are a software developer. So, you know that storage, networking, and domain management have a cost .

If you want to support this blog, please ensure that you have disabled the adblocker for this site. I configured Google AdSense to show as few ADS as possible - I don't want to bother you with lots of ads, but I still need to add some to pay for the resources for my site.

Thank you for your understanding.
- Davide

As you know, I’m a .NET developer. But I think it’s always interesting learning new languages and paradigms, and Python is one of the most popular and versatile languages out there. In this series, I’ll share my journey of learning Python as a .NET developer, and I’ll try to draw parallels between the two ecosystems to make it easier for you (and for me) to understand and move from one ecosystem to the other.

We will start with something very basic and something quite advanced: how to install Python, how to create a virtual environment, how to run a simple “Hello World” program, and how execution works under the hood. Along the way, I’ll also explain some of the key concepts and differences between Python and .NET, such as the compilation process, the runtime, and the standard library.

Consider this post (and, actually, this whole series) as a kind of intro that maps Python and .NET concepts. We will not cover everything that exists in Python, but we will cover just the things that are the most relevant for working with Python while having a background as a .NET developer. Learning about similarities and differences between the two ecosystems is an awesome way to get up to speed with Python.

Here’s the list of the articles in this series:

Let’s begin!

How to install Python on Windows

Depending on your operating system you have several ways to install Python. For Windows 11 users, you can simply download the installer from the official Python website: https://www.python.org/downloads/.

Pay attention that, if you are on Windows, you might have to update the length of the path that Windows allows. In fact, Python can create files with long paths composed of more than 260 characters; if Windows is not configured to allow it, you might get an error like this:

You can be prompted to change the path length

The installer should also ask you if you want to add the Python directory to the system PATHs, allowing you to run Python from the command line. I suggest you do that, as it makes it easier to run Python and pip commands from any terminal.

Installing Python locally also means installing the Python interpreter, the standard library, and the pip package manager, which allows you to install additional packages from the Python Package Index (PyPI).

Think of this like installing the .NET SDK, thanks to which you have dotnet plus the runtime available system-wide.

Python versions, and how to check the installed version

As of today, early 2026, the latest stable version of Python is 3.14. Every new version of Python is supported for 5 years, with a first phase of active development (with new features and bug fixes) and a second phase of security maintenance only.

Python versions

The Python 3.14 release is expected to be supported until October 2030.

You can check the installed version by running python --version in the command prompt.

Virtual Environments: Python’s answer to per-project isolation

In .NET, you typically rely on:

  • Per-project dependency graph resolution (*.csproj, obj/, bin/)
  • NuGet restore into global caches for storing packages system-wide, but with project-level isolation via the project file and the obj/ folder.

Python’s equivalent of local isolation is called virtual environment (venv).

Once you have created the folder that you’re gonna use to store the codebase of your Python project, you can create a virtual environment by running:

python -m venv .venv

That command creates a .venv folder used for the local Python interpreter and for isolated site-packages directories for dependencies.

Virtual environment structure

As you can see, three folders are created: Include, Lib and Scripts. In short:

  • the Include folder contains the header files for the Python C API, which are used when compiling C extensions; even if you’re not compiling C extensions, they are still included in the virtual environment for completeness, and you should not delete that folder;
  • the Lib folder contains the standard library and any installed pip packages;
  • the Scripts folder contains the executables used inside the virtual environment, including executables used for the Python interpreter and for the pip package manager.

There’s something interesting here: after creating it, the virtual environment is just a folder on disk and is not yet activated in your current shell. Activating it mainly updates PATH (and a couple of environment variables) for that terminal session so that commands like python and pip resolve to the ones inside .venv. This is a different model than .NET’s, where the SDK and runtime are available system-wide, and you just need to specify the project file to get the right dependencies.

In the previous example we created a virtual environment in a folder named .venv. Now, if you want to activate it, you can run the following command:

.\.venv\Scripts\activate

If everything went well, you will see the name of the virtual environment in your shell, indicating that the virtual environment is active.

Venv activated

Remember to activate the virtual environment every time you want to work on your project; otherwise, you will use the global Python installation and any packages installed there, which can lead to conflicts and dependency issues.

Finally, given that a venv is just a place for executables and libraries, remember to add it to your .gitignore file, so that you don’t accidentally commit it to your repository.

You can find more information about virtual environments in the official Python documentation, here.

Our first Hello World

In the root of your project, create a file named hello.py, and just type the following code:

print("Hello, World!")

To run it, you can use the command:

python hello.py

That’s another difference with .NET: in .NET you usually create a project, add the files, compile the assembly and run it. In Python, on the contrary, you can run a script file directly.

Well, actually, since .NET 10, we finally have something similar to what we can do with Python: in fact, you can now run a C# file directly with dotnet run file.cs, without the need of scaffolding whole applications. You can read more here.

When you run python hello.py, the Python interpreter reads the hello.py file, compiles it to bytecode, and then executes that bytecode. There’s no need for complex projects or files with a proper file name (like Program.cs), you can just run any Python file directly.

Package management with pip

While in .NET you typically use NuGet for package management, in Python, the most common package installer is pip.

You can search for pip packages on the Python Package Index (PyPI) at https://pypi.org/.

PyPI homepage

On this website, you can find packages for almost anything you can imagine. And, of course, for every package you can find the installation instructions, which usually look like this:

Package installation instructions

Now, depending on whether you are using a virtual environment or not, the installation process is a bit different.

If you are using a virtual environment, you can use:

python -m pip install isOdd

otherwise, if you are using the global Python installation, you can use:

pip install isOdd

But here’s the tricky thing: if you are using a virtual environment, you need to activate it before running pip install, otherwise the package will be installed globally on your system, not in the virtual environment.

In the following screenshot, you can see what happened when I installed the package globally. Even though it is not a recommended approach, it works anyway.

What happens when you install a pip package globally

After downloading the package, you can see information about the installed version and its dependencies, which are also installed automatically.

Notice the path shown in the output: it points to a folder under your AppData directory. That location is pip’s download/cache directory, where wheels and archives are stored, not where the package is ultimately imported from.

The actual installation goes into the global Python interpreter’s site-packages directory. I initially misread the AppData cache path as the install location, which is how I realised I had installed the package into the global environment instead of my virtual environment: I ran pip against the global Python and also forgot to activate the virtual environment before installing the package.

On the contrary, if you are using a virtual environment (and you remembered to activate it before installing the package), the package will be installed in the Lib\site-packages folder of the virtual environment, which is isolated from the global packages.

pip install command in venv

pip package in file system

Finally, to use the package in your code, you can just import it:

from isOdd import isOdd

print(isOdd(0)) 
print(isOdd(5)) Β  Β  
print(isOdd(4)) Β  Β 

If we want to draw a parallel with .NET, we can say that the pip command is more or less equivalent to dotnet add package / nuget install, while the virtual environment is more or less equivalent to a project-local SDK + packages view (they’re not identical, but they have a similar goal: isolation).

The Python execution lifecycle (mapped to .NET concepts)

Ok, but what lies under the hood when you run python hello.py? How does the execution lifecycle work in Python, and how does it compare to .NET’s compilation and runtime model?

What “compilation” means in Python

In .NET, “compile” usually means that the C# code is transformed into IL (Intermediate Language) code and enriched with metadata.

The dotnet build command produces IL assemblies. Then, the dotnet run command runs your app using the runtime. In the meantime, JIT (Just-In-Time) and AOT (Ahead-Of-Time) processes happen at runtime in many scenarios.

Python is an interpreted language, which means that the source code is executed directly by the interpreter, without a separate compilation step to native code. However, this doesn’t mean that there is no compilation at all. A common approach to “compiling” Python code is to compile into Python bytecode (for CPython), which is a lower-level, platform-independent representation of the code that the Python interpreter can execute.

In CPython, generally, the Python source (.py) is transformed into Python bytecode, allowing the interpreter and the underlying Virtual Machine to execute it. CPython also caches bytecode files (.pyc), so it doesn’t have to recompile modules every run; these pre-compiled modules live under __pycache__ and usually improve import and startup time.

So, in short, in Python (when using the Β CPython flow), running python hello.py starts the interpreter process. Then, CPython compiles relevant code to Python bytecode, and then CPython executes that bytecode. In the meantime, cached .pyc may be written/used for imported modules to speed subsequent imports.

.NET’s IL vs CPython’s bytecode

In the .NET world, IL is a well-defined intermediate language that serves as a stable target for compilers and a common execution format for the CLR. It’s designed to be JIT-compiled to native code at runtime, and it includes rich metadata for types, methods, etc.

In Python, the bytecode is a lower-level representation of the source code that the Python interpreter can execute. It’s not designed to be a stable cross-implementation format in the same way IL is, but it’s more of an internal detail of CPython’s execution model, which relies on the Python interpreter VM.

What is the “runtime” in Python?

In .NET, the runtime is the CLR (Common Language Runtime), which executes IL and provides services (Garbage Collector, type system behaviours, etc.) and works with the base libraries.

In Python, the “runtime” you’re usually dealing with is the Python interpreter implementation (yes, it’s CPython again!).

The Python interpreter is responsible for:

  • Loading modules and managing the execution environment
  • Compiling the code to bytecode
  • Executing the bytecode in a VM loop Β 

A difference with .NET is that the CLR often uses JIT compilation to turn IL into native code at runtime, while CPython typically executes bytecode via its interpreter loop, without a JIT step (though there are alternative Python implementations that do JIT, like PyPy).

The BCL equivalent

Microsoft describes the .NET runtime’s standard set of class libraries as runtime libraries, framework libraries, or Base Class Library (BCL).

Python’s closest equivalent is the Python standard library, which is shipped with Python itself (e.g., json, datetime, pathlib, sqlite3, unittest, etc.).

This set of standard elements has a role similar to the BCL: a default, ubiquitous set of APIs that most programs can count on without extra downloads.

Comparison table between .NET and Python concepts

A lot of info, I know.

Let me summarise the key concepts in a quick mapping table, so your brain can relax:

.NET concept Python-ish counterpart Notes
*.cs source *.py source
Compiled language, whose output is an assembly with IL Interpreted language, but CPython allows for compilation into bytecode Python bytecode can be inspected via dis (docs).
CLR CPython interpreter / VM Both execute “intermediate” instructions, but the execution model differs.
JIT (common) Typically interpreter loop (in CPython)
BCL / runtime libraries (System.*) Python standard library Similar “stuff available by default” role, clearly with different packaging and ways of usage.
NuGet packages, mostly from Nuget.org pip packages, mostly from PyPI Β 
dotnet new console (Often) create a folder + main.py manually Python has scaffolding tools, but the default experience is lighter-weight. With .NET 10 you can run single-file scripts.
bin/ + obj/ __pycache__/ + venv folder __pycache__ is where .pyc caches are typically stored.

Further readings

As I mentioned, this article is just an introduction to Python for .NET developers, and it covers just the basics of installation, virtual environments, package management, and execution lifecycle.

I suggest you look at the FAQ page of the official Python documentation, which is a great resource for learning more about Python and its ecosystem:

πŸ”— General Python FAQ | Python docs

For a more interactive and beginner-friendly introduction to Python, you can also check out the Python tutorial on W3Schools:

πŸ”— Python Tutorial | W3Schools

That is the website I will use to learn about Python syntax and basic concepts, as it is very easy to follow and has a lot of examples. Do you have any other resources to suggest for learning Python? Let me know in the comments!

This article first appeared on Code4IT 🐧

Finally, if you are on Windows and you want to learn more about how to use Python on Windows, you can check out the official Python documentation for Windows:

πŸ”— Using Python on Windows | Python docs

Wrapping up

This is the first article of this blog series. However, you can find the other articles of this series here:

As I mentioned, I’m not going to cover every single aspect of Python, but I will cover the most relevant ones for me, as a .NET developer.

I hope that this series will be useful for you if you are a .NET developer looking to learn Python, and that it will help you understand the similarities and differences between the two ecosystems.

Do you have any questions or suggestions for future articles in this series? Let me know in the comments! I’m honestly not sure where this series will go, but I think it will be a fun journey to learn Python and share my findings with you.

I hope you enjoyed this article! Let's keep in touch on LinkedIn, Twitter or BlueSky! πŸ€œπŸ€›

Happy coding!

🐧

About the author

Davide Bellone is a Principal Backend Developer with more than 10 years of professional experience with Microsoft platforms and frameworks.

He loves learning new things and sharing these learnings with others: that's why he writes on this blog and is involved as speaker at tech conferences.

He's a Microsoft MVP πŸ†, conference speaker (here's his Sessionize Profile), content creator on LinkedIn and coordinator of the Torino.NET User Group, in Turin (Italy).