Skip to main content

Installing Python Properly - What Nobody Teaches You

Reading time: ~15 minutes | Level: Foundation → Engineering

Here is a question that reveals whether someone truly understands their environment:

which python
which python3
python --version
python3 --version

Run those four commands. Do they all point to the same interpreter? Do any of them point to /usr/bin/python? Do you know why each answer is what it is?

Most developers cannot fully answer that. And that ignorance causes environment bugs, dependency conflicts, and deployment failures - not because the code is wrong, but because the environment is wrong.

This lesson changes that.

What You Will Learn

  • Why Python is an interpreter, not an application
  • The difference between system Python and your Python - and why this matters
  • How PATH controls everything about which Python runs
  • Why you need pyenv for managing multiple Python versions
  • How virtual environments work at the filesystem level
  • Why pip install X globally is infrastructure malpractice
  • How to make your environment fully reproducible
  • The top 6 installation mistakes that waste hours of debugging time

Prerequisites

  • Access to a terminal (macOS, Linux) or PowerShell (Windows)
  • Basic understanding that Python is a programming language
  • No prior environment management experience needed

The Mental Model: Python Is an Interpreter

Before touching installation, build the right mental model.

When you write print("hello") and run it, something has to read that text and execute it. That something is the Python interpreter - a compiled executable that:

  1. Reads your source code
  2. Tokenizes and parses it into an AST
  3. Compiles it to bytecode
  4. Executes the bytecode via the Python Virtual Machine

"Installing Python" means installing this interpreter.

You can have multiple interpreters installed simultaneously - Python 3.9, 3.11, 3.12 - each completely separate, each with their own packages, each potentially invoked with different commands.

note

The interpreter you run determines everything: the language features available, the standard library version, and which packages are accessible.

Watch: Python Installation Done Right

:::info Video This video covers installing Python correctly on all major platforms, understanding the interpreter, and avoiding the common mistakes that trip up most developers. :::

Part 1 - System Python: Why You Must Not Touch It

On macOS and Linux, Python is already installed. Do not use it for development. Do not install packages into it.

Here is why:

On macOS, Apple controls the system Python. Modifying it can break macOS utilities.

On Ubuntu/Debian, apt manages system Python. Installing conflicting packages with pip into system Python causes package manager failures.

The rule is absolute: system Python is read-only infrastructure. Your code lives in isolated environments.

Verify you are not using system Python:

which python3
# Should NOT be /usr/bin/python3
# Should be something like /home/you/.pyenv/shims/python3
# or /usr/local/bin/python3

python3 -c "import sys; print(sys.executable)"
# Prints the full path to the interpreter being used

Part 2 - PATH: The Mechanism That Controls Everything

PATH is an environment variable - a list of directories the OS searches when you type a command.

echo $PATH
# /home/user/.pyenv/shims:/home/user/.local/bin:/usr/local/bin:/usr/bin:/bin

When you type python3, the OS searches directories left to right until it finds an executable named python3.

This is why which python3 tells you which interpreter wins. The one found first in PATH wins.

Diagnosing PATH Problems

# Which python wins?
which python3

# All python executables on your PATH
type -a python3

# Current PATH
echo $PATH

# From inside Python, where is this interpreter?
python3 -c "import sys; print(sys.executable)"

:::warning Common Mistake "Python works in the terminal but not in my IDE." This is almost always a PATH mismatch - the IDE is using a different Python than your terminal. Check which interpreter your IDE is configured to use. :::

Part 3 - pyenv: Managing Multiple Python Versions

pyenv is the professional tool for managing multiple Python versions on a single machine.

Why pyenv Exists

  • Project A needs Python 3.9
  • Project B needs Python 3.11
  • Your system has 3.8

Without pyenv, you are constantly fighting. With pyenv, each project declares its version and gets it.

Installing pyenv

macOS:

# Install Homebrew first if needed
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# Install pyenv
brew install pyenv

# Add to shell config (~/.zshrc or ~/.bashrc)
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(pyenv init -)"' >> ~/.zshrc

source ~/.zshrc

Linux:

curl https://pyenv.run | bash

# Add to ~/.bashrc or ~/.bash_profile
export PYENV_ROOT="$HOME/.pyenv"
command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"

source ~/.bashrc

Using pyenv

# See available Python versions
pyenv install --list | grep " 3\."

# Install a specific version
pyenv install 3.11.9
pyenv install 3.12.4

# List installed versions
pyenv versions

# Set global default
pyenv global 3.11.9

# Set version for current directory only (saved to .python-version file)
pyenv local 3.11.9

# Verify
python3 --version # 3.11.9

The .python-version file travels with your project and tells pyenv which Python to use in that directory:

cat .python-version
# 3.11.9

This is version pinning at the environment level. Anyone who clones your project and has pyenv installed gets the exact same Python version.

Part 4 \text{---} Virtual Environments: Isolation Is Not Optional

Even with the right Python version, if you install packages globally, you create conflicts between projects.

A virtual environment is an isolated Python installation \text{---} a directory containing:

myproject/
└── venv/
├── bin/
│ ├── python3 ← symlink to your pyenv Python
│ ├── pip3
│ └── activate
├── lib/
│ └── python3.11/
│ └── site-packages/
│ ├── requests/ ← installed here, not globally
│ └── numpy/
└── pyvenv.cfg

Every package installed with pip goes into venv/lib/ \text{---} completely separate from other projects.

Creating and Using a Virtual Environment

# Navigate to your project
cd myproject

# Create virtual environment (using pyenv's Python)
python3 -m venv venv

# Activate (macOS/Linux)
source venv/bin/activate

# Activate (Windows PowerShell)
venv\Scripts\Activate.ps1

# Your prompt now shows (venv)
(venv) $ python --version # Uses venv Python
(venv) $ which python # Points to venv/bin/python

# Install packages \text{---} goes into venv only
(venv) $ pip install requests numpy pandas

# Deactivate when done
(venv) $ deactivate

Why This Matters

Without virtual environments - a single global package space causes conflicts:

PackageVersionRequired by
requests2.25Project A
requests2.31Project B

Only one version can be installed globally - CONFLICT.

With virtual environments - each project has its own isolated package space:

project_a/venv/project_b/venv/
requests==2.25requests==2.31
flask==2.0django==4.2
numpy==1.21numpy==1.26
Isolated - no conflictIsolated - no conflict
danger

Never use sudo pip install. Never install packages globally. If you find yourself doing this, you have the wrong mental model for Python package management.

Watch: Virtual Environments Explained

Part 5 - pip: Package Manager Deep Dive

pip installs packages from PyPI (Python Package Index). Understanding what pip does matters for debugging.

pip Basics

# Install a package
pip install requests

# Install specific version
pip install requests==2.31.0

# Install minimum version
pip install "requests>=2.28.0"

# Upgrade a package
pip install --upgrade requests

# Uninstall
pip uninstall requests

# List installed packages
pip list

# Show package details
pip show requests

Verifying the Right pip

There can be multiple pip executables on your system. Always verify:

# Which pip?
which pip
# Should point inside your venv or pyenv environment

# Verify pip matches your Python
pip --version
# pip 24.0 from /path/to/venv/lib/python3.11/... (python 3.11)

# Safest form - uses the specific Python's pip
python -m pip install requests

The python -m pip form is explicit: it uses the pip associated with the Python interpreter you just invoked.

Freezing and Reproducing Environments

The professional workflow uses requirements files:

# Capture current environment state
pip freeze > requirements.txt

# Later, reproduce that exact environment
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt

The requirements.txt looks like:

certifi==2024.2.2
charset-normalizer==3.3.2
idna==3.6
numpy==1.26.4
requests==2.31.0
urllib3==2.2.1

Every package pinned to an exact version. Reproducible across machines, across time, across teammates.

tip

For modern projects, consider pyproject.toml with pip-tools or poetry for more sophisticated dependency management. But requirements.txt remains universal.

Part 6 - Verifying Your Installation

After setup, always verify:

import sys

print(f"Python: {sys.version}")
print(f"Executable: {sys.executable}")
print(f"Path: {sys.path}")

# Check you are in a virtual environment
import os
in_venv = sys.prefix != sys.base_prefix
print(f"In virtual environment: {in_venv}")
print(f"Venv path: {sys.prefix if in_venv else 'N/A'}")
# Verify a package is accessible
import importlib
packages_to_check = ['numpy', 'requests', 'pandas']

for pkg in packages_to_check:
spec = importlib.util.find_spec(pkg)
status = "OK" if spec else "NOT FOUND"
print(f"{pkg}: {status}")

Common Installation Mistakes - Top 6

Mistake 1: Using System Python

# Wrong: modifying system Python
sudo pip install requests

# Right: use a virtual environment
python3 -m venv venv && source venv/bin/activate && pip install requests

Mistake 2: Forgetting to Activate the Virtual Environment

# You think you're installing into venv but you're not
pip install requests # without activating venv first

# Symptoms:
# - Package installs but import fails in your IDE
# - "where did I install that?" confusion

# Fix: always check your prompt for (venv) prefix
# Or check: which python && which pip

Mistake 3: Committing the venv/ Directory to Git

# Wrong: committing thousands of package files
git add venv/

# Right: add to .gitignore
echo "venv/" >> .gitignore
echo ".venv/" >> .gitignore
echo ".python-version" >> .gitignore # optional, often committed

Commit requirements.txt (or pyproject.toml), not the environment itself.

Mistake 4: Mixing Python 2 and Python 3

On some systems, python means Python 2 and python3 means Python 3.

python --version # 2.7.18 ← old
python3 --version # 3.11.9 ← what you want

# Always use python3 explicitly
# Or set pyenv global to a 3.x version

Mistake 5: Not Pinning Versions

# requirements.txt - wrong (floating)
requests
numpy

# requirements.txt - right (pinned)
requests==2.31.0
numpy==1.26.4

Unpinned requirements mean your environment changes when packages release new versions. That breaks reproducibility and causes "but it worked on my machine" failures.

Mistake 6: Ignoring Interpreter Path in IDEs

VS Code, PyCharm, Jupyter - all need to be told which interpreter to use.

# VS Code: Ctrl+Shift+P → "Python: Select Interpreter"
# Choose the one inside your venv

# Verify from inside IDE terminal:
python -c "import sys; print(sys.executable)"
# Must match your venv path

AI/ML Real-World Connection

Python environment management is not just for web development. It is mission-critical in machine learning:

# ML environments have tight version constraints
# NumPy 1.24+ changed behavior of certain operations
# TensorFlow 2.x requires specific CUDA versions
# PyTorch has different builds for CPU vs GPU

# A requirements.txt for ML might look like:
# numpy==1.26.4
# pandas==2.2.1
# scikit-learn==1.4.1
# torch==2.2.1+cu121 # PyTorch with CUDA 12.1
# transformers==4.38.2

# Mismatched versions cause:
# - Silent numerical errors (different NumPy behavior)
# - Import failures (TF/PyTorch CUDA mismatches)
# - Deprecation crashes (scikit-learn API changes)

In production ML systems, environments are often containerized with Docker to guarantee reproducibility across training clusters and inference servers.

Interview Questions

Q1: What is the difference between system Python and a user-installed Python?

Answer: System Python is installed and managed by the operating system (macOS, Linux). It is used by OS tools and scripts and should not be modified. User-installed Python (via pyenv, Homebrew, or official installers) is separate and controlled by the developer. Always use user-installed Python for development work.

Q2: What does PATH do and why does it matter for Python?

Answer: PATH is an environment variable containing a list of directories the OS searches when you type a command. When you type python3, the OS finds the first python3 executable in the directories listed in PATH. Managing PATH order determines which interpreter wins, which is why pyenv puts its shims directory at the front of PATH.

Q3: What does a virtual environment actually contain?

Answer: A virtual environment is a directory with: a Python interpreter (or symlink to one), its own pip, and a site-packages directory for installed libraries. Activating a venv prepends the venv's bin/ directory to PATH, making that Python and pip take precedence. All packages installed go into the venv's site-packages, not globally.

Q4: Why is python -m pip install safer than pip install?

Answer: python -m pip explicitly runs the pip associated with the currently active Python interpreter. Plain pip can be ambiguous - on some systems, pip might point to a different Python's pip than python. Using python -m pip eliminates the ambiguity.

Q5: What is pip freeze and when should you use it?

Answer: pip freeze outputs all installed packages and their exact versions in name==version format. Running pip freeze > requirements.txt captures a complete snapshot of your environment. Use it to share environments with teammates, deploy to servers, or restore an environment later. It is the standard reproducibility tool.

Q6: What is pyenv and why use it over the official Python installer?

Answer: pyenv manages multiple Python versions on a single machine and allows switching between them per-directory (via .python-version files). Unlike the official installer, which installs a single global version, pyenv lets you run Python 3.9 for one project and 3.12 for another without conflicts. It also does not modify system Python.

Quick Reference Cheatsheet

TaskCommand
Install pyenv (macOS)brew install pyenv
Install Python versionpyenv install 3.11.9
Set global Pythonpyenv global 3.11.9
Set project Pythonpyenv local 3.11.9
Create virtual environmentpython3 -m venv venv
Activate (macOS/Linux)source venv/bin/activate
Activate (Windows)venv\Scripts\Activate.ps1
Deactivatedeactivate
Install packagepip install package_name
Save environmentpip freeze > requirements.txt
Restore environmentpip install -r requirements.txt
Which Python?which python3
Which interpreter exactly?python -c "import sys; print(sys.executable)"
In a venv?python -c "import sys; print(sys.prefix != sys.base_prefix)"

Graded Practice Challenges

Level 1 - Predict the Output

Given this terminal session, what does the last command print?

cd /tmp
python3 -m venv testenv
source testenv/bin/activate
pip install requests==2.25.0
pip freeze | grep requests
Show Answer

Output: requests==2.25.0

pip freeze outputs exactly installed packages and their pinned versions. Since requests==2.25.0 was installed, that is what prints. This demonstrates version pinning behavior.

Level 2 - Debug the Environment

A developer reports: "I installed numpy but import numpy fails in Jupyter."

What are the three most likely causes and how would you diagnose each?

Show Answer

Cause 1: Jupyter is using a different Python/kernel than where numpy was installed.

Diagnosis: In Jupyter, run:

import sys
print(sys.executable)

Compare to where you installed numpy.

Cause 2: You installed numpy without activating the virtual environment.

Diagnosis: Check whether pip install numpy was run with (venv) prefix in terminal.

Cause 3: Jupyter kernel is not pointing to the venv.

Fix: Inside the venv, install the kernel:

pip install ipykernel
python -m ipykernel install --user --name=myenv

Then select "myenv" kernel in Jupyter.

Level 3 - Design Challenge

You are setting up a Python development environment for a team of 5 engineers who will work on an ML project requiring:

  • Python 3.11 exactly
  • NumPy 1.26 (specific for a CUDA build)
  • PyTorch 2.1 (GPU version)
  • The ability to onboard new teammates in under 10 minutes

Design the complete setup: what files you create, what commands are in the README, and how you guarantee reproducibility.

Show Answer

Setup design:

# .python-version (pyenv)
echo "3.11.9" > .python-version

# requirements.txt (pinned)
numpy==1.26.4
torch==2.1.2+cu121
scikit-learn==1.4.0
pandas==2.2.0

README setup section:

# Prerequisites: pyenv installed

# 1. Clone repo
git clone https://github.com/org/ml-project

# 2. pyenv auto-selects Python 3.11.9 (from .python-version)
cd ml-project
python --version # 3.11.9

# 3. Create and activate venv
python -m venv venv
source venv/bin/activate # or venv\Scripts\activate on Windows

# 4. Install pinned dependencies
pip install -r requirements.txt

# 5. Verify
python -c "import torch; print(torch.__version__)" # 2.1.2+cu121

Reproducibility guarantees:

  • .python-version pins Python via pyenv
  • requirements.txt pins all packages
  • venv/ is in .gitignore
  • Onboarding is 4 commands, not 40 decisions

Key Takeaways

  • Python is an interpreter - installing Python means installing an executable program that runs your code
  • System Python is off-limits for development - it belongs to the OS
  • PATH determines which Python runs when you type a command - manage it deliberately
  • pyenv manages multiple Python versions cleanly, with per-project version pinning via .python-version
  • Virtual environments are mandatory - one per project, never shared, never committed to git
  • pip freeze > requirements.txt is the standard reproducibility tool
  • python -m pip is safer than bare pip - avoids interpreter ambiguity
  • A good environment is reproducible in minutes by any teammate on any machine
  • ML projects have especially tight version requirements - environment discipline is not optional there
© 2026 EngineersOfAI. All rights reserved.