pip
pip is Python's standard package installer — the tool that fetches, installs, upgrades, and removes third-party libraries from PyPI or other indexes.
pip is the reference package installer for Python. It downloads distributions (wheels or source distributions) from a package index — by default the Python Package Index, PyPI — resolves their dependencies, and installs them into whichever interpreter's site-packages it is invoked against. pip has shipped with the standard CPython installers since Python 3.4.
What pip Does
pip is invoked as pip <command> ... or, more robustly, as python -m pip <command> ... — the latter form guarantees you're using the pip tied to the specific interpreter you named, which matters when multiple Python installations or virtual environments are present.
python -m pip --version
python -m pip install requestsPackage Installation
The basic form installs the latest compatible release of a named package and everything it depends on.
Always quote version specifiers that contain < or > on shells (like bash) where those characters mean redirection.
pip install requests
pip install requests beautifulsoup4 # multiple packages
pip install requests==2.31.0 # exact version
pip install "requests>=2.28,<3" # constrained range
pip install -e . # editable install of the current project
pip install package_name --no-deps # skip installing dependenciesRequirements Files
A requirements file lists packages (one per line, optionally version-constrained) so an entire set of dependencies can be installed with a single command — the standard way to share and reproduce a project's dependency set.
# requirements.txt
requests==2.31.0
click>=8.0,<9
python-dateutilpip install -r requirements.txtVersion Constraints
pip understands the version specifiers defined by PEP 440. The common operators:
Pinning too loosely (no upper bound) risks a future release silently breaking your project; pinning too tightly (only ==) makes upgrades and security patches harder to apply. Libraries typically use loose, compatible ranges; applications typically pin exact versions via a lock file (see Dependency Management).
==2.31.0 exactly this version
>=2.28 at least this version
<3.0 strictly below this version
>=2.28,<3.0 a bounded range (combine with a comma)
~=2.28 "compatible release": >=2.28, <2.29 (only the last segment may increase)
!=2.30.0 any version except this oneUpgrading Packages
Upgrading one package can pull in newer versions of its dependencies too, since pip's resolver must keep the whole installed set consistent.
pip install --upgrade requests
pip install -U requests # short form
python -m pip install --upgrade pip # upgrading pip itselfUninstalling Packages
pip uninstall removes only the named package(s), not their now-unused dependencies (there is no automatic 'autoremove').
pip uninstall requests
pip uninstall -r requirements.txt -y # uninstall everything listed, no promptInspecting What's Installed
pip list # everything installed in this environment
pip show requests # metadata + dependencies for one package
pip freeze # pip-install-ready "name==version" lines
pip check # verify installed packages' dependencies are satisfiedPackage Indexes
By default pip fetches from PyPI (pypi.org). Organizations often run a private or mirrored index (for internal packages, or to control what versions are approved) and point pip at it instead of, or in addition to, PyPI.
--index-url replaces the default index entirely; --extra-index-url adds another index pip may also search — the latter has a well-known security footgun covered next.
pip install mypkg --index-url https://pypi.company.internal/simple/
pip install mypkg --extra-index-url https://pypi.company.internal/simple/Security Considerations
Installing a package runs arbitrary code (build scripts, and the package's own code once imported), so supply-chain integrity matters.
Dependency confusion: using --extra-index-url alongside PyPI can let an attacker publish a same-named malicious package to public PyPI with a higher version number, which pip may then prefer over your intended private package. Prefer --index-url pointed at a proxying private index that also mirrors PyPI, or pin exact versions/hashes, rather than mixing indexes casually.
Hash checking: pip install --require-hashes -r requirements.txt (with hashes recorded in the file) makes pip refuse to install anything whose downloaded file doesn't match the recorded cryptographic hash, defending against a compromised or substituted package file.
Other habits: install from trusted indexes only, review a package's popularity/maintenance before adopting it, avoid running pip install as an administrator/root user when a virtual environment would do, and keep pip itself updated to receive security fixes.
# requirements.txt with hashes (typically generated by a tool, not by hand)
requests==2.31.0 \
--hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988bce1adf30c9d3dPractical Usage
A typical day-to-day sequence inside an activated virtual environment:
python -m pip install --upgrade pip # keep pip itself current
pip install -r requirements.txt # restore a project's dependencies
pip install black --upgrade # add or update a dev tool
pip freeze > requirements.txt # capture the current state
pip check # sanity-check the environmentEdge Cases
Installing without an active virtual environment installs into whichever interpreter pip/python -m pip resolves to — potentially the system Python, which some OS package managers actively protect against (an 'externally managed environment' error on modern Debian/Ubuntu, for instance).
Two packages that require incompatible versions of a shared dependency produce a resolution failure (or, with an older resolver, a silent broken install) — see Dependency Management for how lock files and conflict resolution address this.
pip install from a local path or VCS URL (pip install git+https://...) is possible and common for installing unreleased or private code, but bypasses the index entirely.
Best Practices
Always work inside a virtual environment. Prefer python -m pip over a bare pip to be certain which interpreter is targeted. Pin dependencies for applications; use loose, tested ranges for libraries. Run pip check after manual installs. Use hash-checking or a lock file for anything security-sensitive or production-bound. Keep pip itself upgraded.
Complete Example
python -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
pip install "requests>=2.28,<3" click
pip list
pip show requests
pip freeze > requirements.txt
pip uninstall click -y
pip checkQuick Reference
install NAME install latest matching version
install NAME==X.Y.Z install exact version
install -r FILE install from a requirements file
install -U NAME upgrade
install -e . editable install of the local project
uninstall NAME remove a package
list show installed packages
show NAME show one package's metadata/dependencies
freeze print "name==version" for all installed packages
check verify installed dependency graph is consistentKey Takeaways
pip installs from a package index (PyPI by default), resolving and installing dependencies along with the requested package.
python -m pip is safer than a bare pip because it ties the command to a specific interpreter unambiguously.
Version specifiers (PEP 440) express exact pins, ranges, and compatible-release constraints.
requirements.txt plus pip freeze/pip install -r is the baseline way to share and reproduce a dependency set.
Installing runs code, so index trust, hash verification, and avoiding mixed public/private indexes are real security concerns, not formalities.
pip install pandas # unclear which interpreter's pip this is python -m pip install pandas # unambiguously targets THIS python
A bare pip on PATH may resolve to a different interpreter than the one you intend (e.g. system Python instead of an active venv) — python -m pip removes that ambiguity.
pip install "requests" # no version constraint at all, in an application
An unpinned dependency in an application can silently change behavior on the next install as PyPI releases new versions; applications should pin, while only libraries typically use open-ended ranges.
pip install mypkg --extra-index-url https://internal.example/simple/ # and mypkg also exists publicly on PyPI under the same name pip install mypkg --index-url https://internal.example/simple/ # a private index that itself mirrors/proxies PyPI
Combining --extra-index-url with a public index invites dependency confusion: an attacker's higher-versioned public package with the same name can be installed instead of your private one.
Why is python -m pip install X generally preferred over pip install X?
It guarantees the install targets the specific interpreter you named, avoiding ambiguity when multiple Python installations or a virtual environment are on PATH.
What is the difference between >=2.28,<3 and ~=2.28?
>=2.28,<3 allows any version from 2.28 up to (but not including) 3.0; ~=2.28 means 'compatible release' and only allows the version to move forward within the same 2.28.x-style final segment, roughly equivalent to >=2.28,<2.29 for a two-part version.
What does pip freeze produce, and what is it typically used for?
It prints every installed package and its exact version as name==version lines, typically redirected into a requirements.txt so the environment can be recreated elsewhere.
Why can --extra-index-url be a security risk?
If a package name exists on both a private index and public PyPI, pip may select the higher-versioned release, letting an attacker publish a malicious same-named package publicly and have it chosen over the intended private one — dependency confusion.
What does pip check do, and when would you run it?
It verifies that every installed package's declared dependencies are actually satisfied by what's installed, without installing anything — useful after manual or unusual installs to catch a broken dependency graph.
Does pip uninstall remove a package's now-unused dependencies too?
No — it removes only the named package(s); pip has no automatic 'autoremove' of orphaned dependencies.
How would you make pip refuse to install a package whose downloaded file doesn't match an expected checksum?
Use pip install --require-hashes -r requirements.txt with a requirements file that records --hash entries for each package.
Write the pip commands to: install exactly requests version 2.31.0, upgrade click to its latest version, and then list everything currently installed.
pip install requests==2.31.0 pip install --upgrade click pip list install requests==2.31.0 pins an exact version; --upgrade click fetches click's newest compatible release; pip list enumerates every package installed in the current environment.
Given this requirements.txt, what single pip command installs everything it lists?
pip install -r requirements.txt — it reads the file and installs each listed package under its given constraint.
Write a short requirements.txt entry (as a comment) explaining why numpy with no version constraint is risky for an application but might be acceptable for a library, and show a safer application-style pin.
Applications want reproducible, exact installs (pin with ==); libraries generally want compatibility across a range of versions so they don't over-constrain whoever installs them.
# requirements.txt
flask>=2.0,<3
requests==2.31.0