Python’s package ecosystem is its superpower, and pip is the gatekeeper.
import requests
print(requests.__version__)
To get requests if you don’t have it:
python3 -m pip install requests
This command tells Python (using python3 -m) to run the pip module and execute its install command, fetching the requests package from the Python Package Index (PyPI) and placing it in your current Python environment’s site-packages directory.
Managing packages is about more than just installing. You can list what’s installed:
python3 -m pip list
This will output a table of installed packages and their versions. To see just the packages and their versions in a format suitable for re-installation:
python3 -m pip freeze
This is crucial for reproducibility. If you have a project with specific dependencies, you can capture them:
python3 -m pip freeze > requirements.txt
Later, on another machine or in a fresh virtual environment, you can install all those exact versions:
python3 -m pip install -r requirements.txt
This requirements.txt file is the bedrock of reproducible Python development.
Virtual environments are the standard way to isolate project dependencies. If you don’t use them, pip install will put packages into your global Python installation, leading to version conflicts when different projects need different versions of the same library.
To create a virtual environment:
python3 -m venv myproject_env
This creates a myproject_env directory containing a copy of the Python interpreter and a clean site-packages directory. To activate it:
- On macOS/Linux:
source myproject_env/bin/activate - On Windows (Command Prompt):
myproject_env\Scripts\activate.bat - On Windows (PowerShell):
myproject_env\Scripts\Activate.ps1
Once activated, your shell prompt will change, indicating you’re in the virtual environment. Now, pip install commands will only affect this isolated environment.
(myproject_env) $ python -m pip list
The output will be minimal, showing only pip and setuptools.
To uninstall a package:
(myproject_env) $ python -m pip uninstall requests
pip will ask for confirmation.
The real magic of pip is its ability to resolve dependencies. When you install requests, it might also pull in charset-normalizer, idna, urllib3, and certifi because requests depends on them. pip figures this out by inspecting the metadata of the requested package.
When you execute python3 -m pip install some-package, pip first queries the Python Package Index (PyPI) for some-package. It retrieves its metadata, which includes a list of other packages it requires, along with their version constraints. pip then recursively queries for these dependencies, ensuring that compatible versions of all required packages are installed. It builds a dependency graph and then installs the packages in an order that satisfies all constraints, downloading them from PyPI and placing them into the site-packages directory of the active Python environment.
If you need a specific version, you can specify it:
(myproject_env) $ python -m pip install "django==4.1.7"
Or a minimum version:
(myproject_env) $ python -m pip install "django>=4.0"
Or a range:
(myproject_env) $ python -m pip install "django>=4.0,<5.0"
The requirements.txt file is just a plain text file. The format is package_name[==|>=|<=|~=]version. The ~= operator, for example, allows for compatible upgrades within a minor version. ~=4.1.7 is equivalent to >=4.1.7,<4.2.0. This fine-grained control is essential for managing complex projects.
You can also upgrade a package:
(myproject_env) $ python -m pip install --upgrade requests
This tells pip to find the latest compatible version of requests and install it, updating the existing one if necessary.
The pip command itself can sometimes be updated. If you encounter strange errors with pip, try upgrading it:
python3 -m pip install --upgrade pip
This ensures you’re using the latest bug fixes and features of the package installer itself.
When pip install runs, it downloads wheels (pre-compiled binary distributions) or source distributions (sdist) from PyPI. For wheels, it’s a simple extraction into site-packages. For sdists, it might involve compiling code, which requires build tools like C compilers to be present on your system. This is why installing packages like numpy or pandas can sometimes fail on a clean system if the necessary build dependencies aren’t installed first.
The ability to pin exact versions in requirements.txt is a double-edged sword. While it guarantees reproducibility, it can also lead to "dependency hell" if a critical dependency is no longer maintained or has security vulnerabilities. Regularly reviewing and updating your dependencies, perhaps using tools like pip-audit or dependabot, is a crucial part of maintaining a healthy project.
The next hurdle is often managing different Python versions alongside different package environments, which is where tools like pyenv or conda come into play.