Why
Python keeps installed packages in one folder, site-packages. Every project run by that Python shares it. If one project needs version 1 of a package and another needs version 2, only one fits, and the projects clash.
Make a venv
python3 -m venv .venv makes a virtual environment: a folder named .venv with its own python, which points back to the system one, and its own site-packages that holds only pip.
source .venv/bin/activate puts .venv/bin first in PATH, the list of folders your shell searches for commands. Now python and pip mean the copies in .venv, and the prompt starts with (.venv).
Install with pip
requirements.txt lists the packages a project needs, one per line. requests==2.32.3 asks for exactly version 2.32.3 of requests, a popular library for fetching web pages, so every copy of the project gets the same code.
pip install -r requirements.txt reads the list and downloads requests 2.32.3 from PyPI, the Python Package Index, plus the 4 packages requests needs. All of them land in .venv's site-packages, and nowhere else.
python app.py now runs .venv's python. Its import requests searches sys.path, the list of folders import looks in, which includes .venv's site-packages, finds the package there, and the program prints its version: 2.32.3.
Isolation
deactivate undoes activate: PATH and the prompt go back to how they were, so python3 means the system Python again. The .venv folder stays on disk, ready for the next time you activate it.
python3 app.py now runs the system Python. Here its site-packages has no requests, and it never looks inside .venv, so the import fails with ModuleNotFoundError. Each environment is isolated, so projects cannot break each other.
A venv is disposable: do not copy it or put it in Git. On a new computer, or after deleting .venv, run lines 1 to 3 again. pip reads requirements.txt and you get the same packages back.
Try it yourself
;; step 1/9 >>> import site >>> site.getsitepackages() # example, macOS ['/opt/homebrew/lib/python3.14/site-packages', ...] # pip puts packages here; every project that # runs this Python sees the same folder
On macOS and Linux the command is often python3; inside an activated venv plain python works too. On Windows use py -m venv .venv to create one. The last step assumes the system Python does not have requests. If it does, python3 app.py works there too. Isolation runs both ways: the system Python never looks inside .venv, and by default (include-system-site-packages = false) a venv does not see the system's packages.