Skip to content

Virtual Environments & pip Interview Questions & Answers

15 questions Updated 2026-06-18 Share:

Python interview questions on virtual environments and pip — what a venv is and why isolation matters, creating and activating one, requirements.txt, pip freeze, editable installs, and pyproject.toml.

Read the in-depth guidePython Virtual Environments & pip Explained — venv, Dependency Isolation, and Reproducible Installs(opens in new tab)
15 of 15

A virtual environment is a self-contained directory with its own Python interpreter and its own site-packages, so each project gets an isolated set of dependencies. Isolation matters because two projects often need different versions of the same package — without venvs, installing for one breaks the other, and installing globally can even break system tools.

# Project A needs Django 3, Project B needs Django 5.
# Separate venvs let both coexist without conflict.
python -m venv .venv        # creates an isolated environment

A venv keeps dependencies per project and out of the global interpreter, making builds reproducible and avoiding "works on my machine" version clashes. Use one for every project.

Create one with the standard-library venv module, then activate it so the shell uses the venv's python and pip. The activation command differs by OS; deactivate returns to the global interpreter.

python -m venv .venv            # create (folder named .venv)

source .venv/bin/activate       # activate on macOS / Linux
.venv\Scripts\activate          # activate on Windows

which python                    # -> .../.venv/bin/python while active
deactivate                      # leave the venv

Once active, pip install puts packages inside the venv only. Add .venv/ to .gitignore — you commit the dependency list, not the environment itself.

pip install fetches packages from PyPI into the active environment. A requirements.txt lists a project's dependencies (often with pinned versions) so anyone can recreate the same environment with one command.

pip install requests            # install latest
pip install "requests==2.31.0"  # install a specific version

pip install -r requirements.txt # install everything listed in the file
# requirements.txt
requests==2.31.0
rich>=13.0

Committing requirements.txt makes installs reproducible across machines and CI. Install into an activated venv, never globally with sudo pip.

pip freeze prints every installed package with its exact pinned version in requirements.txt format, so you can capture the current environment. Redirect it to a file to snapshot dependencies.

pip freeze                          # list installed pkgs == versions
pip freeze > requirements.txt       # snapshot the current environment
pip list                            # similar, but human-readable table

A caveat: pip freeze records everything installed, including transitive dependencies, which can make the file noisy. Many teams instead hand-curate direct dependencies (or use a lock-file tool) and keep pip freeze for capturing a known-good full snapshot.

An editable install links your project into the environment in place instead of copying it, so edits to the source take effect immediately without reinstalling. It's the standard way to work on a package you're developing locally.

pip install -e .                # install the current project, editable
pip install -e ".[dev]"         # editable + optional 'dev' extras

Because the install points at your working tree, changing the code updates the imported package right away — no rebuild needed. Use -e for your own package under development, and a normal pip install for third-party dependencies.

pyproject.toml is the modern, standardized config file (PEP 518/621) for a Python project — it declares the build system, project metadata, and dependencies in one place, replacing the older setup.py/setup.cfg split. Most modern tools (build, pip, linters, formatters) read it.

[project]
name = "myapp"
version = "0.1.0"
dependencies = ["requests>=2.31", "rich"]

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

With dependencies declared here, pip install . (or -e .) reads them directly, so a separate requirements.txt becomes optional. It's the recommended starting point for any new packaged project.

Activation prepends the venv's bin/Scripts directory to PATH and sets VIRTUAL_ENV, so python and pip resolve to the venv's copies first. The venv's pyvenv.cfg points back to the base interpreter; there's no magic beyond PATH.

source .venv/bin/activate
echo $PATH            # .venv/bin is now first
which python          # .../.venv/bin/python
echo $VIRTUAL_ENV     # path to the venv

Rule of thumb: a venv is mostly a PATH trick + isolated site-packages; you can even skip activation by calling .venv/bin/python directly.

venv is built into the stdlib and manages Python packages for one Python version. virtualenv is a faster third-party superset (supports older Pythons, more features). conda is a separate ecosystem that also manages non-Python binaries and Python itself.

python -m venv .venv          # stdlib, simplest
virtualenv .venv              # third-party, more features
conda create -n myenv python=3.12 numpy   # manages Python + native deps

Rule of thumb: use venv for most projects; conda when you need complex native/ scientific binaries or to manage the Python version itself.

Specifiers constrain acceptable versions: == exact, >= minimum, ~= "compatible release" (allows the last digit to grow), and != to exclude. They balance reproducibility against getting fixes.

requests==2.31.0     # exactly this version
requests>=2.28       # this or newer
requests~=2.31.0     # >=2.31.0, <2.32.0  (compatible release)
requests>=2.0,<3.0   # range

Rule of thumb: pin exact (==) versions in a lock/deploy file for reproducibility; use ranges (>=, ~=) for libraries to stay compatible with users' other deps.

pipx installs Python applications (CLI tools) each into their own isolated venv while exposing the command globally — avoiding dependency clashes in your base environment. Use pip for libraries your project imports.

pipx install black           # global `black` command, isolated deps
pipx install httpie
pip install requests         # a library to import in your code

Rule of thumb: pipx for standalone tools you run (linters, formatters, CLIs); pip (inside a venv) for packages you import.

Pip's resolver finds a set of versions satisfying all constraints (direct and transitive); it errors on conflicts. Because requirements.txt may not pin everything, lock files (pip-tools, Poetry, uv) record the exact resolved versions for fully reproducible installs.

pip install -r requirements.txt   # resolver picks compatible versions
pip-compile requirements.in       # -> pinned requirements.txt (lock)
uv lock                           # modern lock-file workflow

Rule of thumb: use a lock file (compiled pins) for apps/deploys so every install is identical; loose ranges are for libraries that must coexist with others.

Installing globally as root can overwrite or break system packages that the OS depends on, and mixes project deps into the system Python. Use a venv (or pip install --user) instead so installs stay isolated and reversible.

sudo pip install foo        # risky: can clobber system Python packages
python -m venv .venv && source .venv/bin/activate && pip install foo  # safe

Rule of thumb: never sudo pip; isolate with a venv. Modern Linux even blocks global pip installs (PEP 668 "externally-managed-environment") to prevent this.

Use pip install --upgrade (or -U) to update, and pip uninstall to remove. pip show inspects a package; pip list --outdated finds upgradable ones.

pip install --upgrade requests     # update to the latest allowed
pip install -U pip                 # upgrade pip itself
pip uninstall requests             # remove (asks to confirm)
pip list --outdated                # what can be upgraded
pip show requests                  # version, location, dependencies

Rule of thumb: pip uninstall doesn't remove a package's dependencies — use a lock/clean reinstall or a tool like pip-autoremove to prune orphans.

Put abstract dependencies (ranges) in pyproject.toml for a library/package others install. Use requirements.txt (often pinned) for an application/ deployment environment you control. They serve different audiences.

# pyproject.toml — library deps, loose
dependencies = ["requests>=2.28", "click"]
# requirements.txt — app deploy, pinned
requests==2.31.0
click==8.1.7

Rule of thumb: pyproject.toml declares what your package needs; requirements.txt (or a lock file) records the exact environment to reproduce for an app.

Pip caches downloaded wheels so repeat installs are fast and don't re-download. You can build a local wheelhouse with pip download and install from it offline with --no-index --find-links.

pip cache dir                       # where wheels are cached
pip install --no-cache-dir foo      # bypass the cache
pip download -r requirements.txt -d wheels/    # fetch wheels for offline use
pip install --no-index --find-links=wheels/ -r requirements.txt

Rule of thumb: rely on the cache for speed; use pip download + --find-links to install on air-gapped/offline machines reproducibly.

More ways to practice

The self-quiz is live. Join our channel for updates, new content & tech tips.

Join our WhatsApp Channel