[Django]-Difference between 'python -m pip install <package-name>' and 'pip install <package-name>'

3👍

Welcome to the world of symlinks, binary discoverability with PATH, and shebang #!/... (*nix).

Before getting into the weaves of it all, let’s talk about what pip is:

pip is both a python module (i.e python -m pip (the -m mean module)) and a binary $ pip. pip as a binary (the program) is optional, it’s not required. pip as the module (inside site-packages where all the python modules are installed) is ABSOLUTELY required! Without it nothing will work, or worse yet you would use the pip module from another python version you have installed and then you’re really going to slam your head against the wall…

PATH variable

echo $PATH (*nix) will show you something like this:

$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

That means that the system, through the terminal will look for the binaries first inside /usr/local/bin then /usr/bin then … so on. If it found it in the first place it looked, great, it’s done, no need to keep searching. You can have the same binary name in different directories, the order of PATH is what matters, the second one will never be executed, EVER.

Why am I mentioning this? Well let’s say you installed multiple versions of python or pip, and you installed it in the wrong place? Where the order is wrong? Well that binary will not run as expected.

Symlinks

You can have different versions of pip and python — they’re independent from one another, meaning just because you’re using python with version 3.8, does not mean your pip is pointing to the same python binary.

A quick way to check is to do: (this applies to pip)

$ ls -ls $(which python)
0 lrwxr-xr-x  1 root  wheel  75 Jan  1  2020 /usr/bin/python -> ../../System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7

You can see it’s using the system version of python and any other version I have are being ignored if I just run python, I can "fix" this by specifying the version number such as python3.8

You can fix this one by first figuring out what binaries you have available to you:

$ echo $PATH | sed 's/:/ /g' | xargs -n1 -I{} find {} -name 'python*' | grep -v 'config$'
/usr/local/bin/python3
/usr/local/bin/python3.9
/usr/local/bin/python3.8
/usr/bin/python3
/usr/bin/python
/usr/bin/python2
/usr/bin/pythonw
/usr/bin/pythonw2.7
/usr/bin/python2.7

Say I want my default python to be python3.8, then do:

$ ln -s /usr/local/bin/python3.8 /usr/local/bin/python
$ hash -r

hash -r tells the the terminal to forget all the banaries it found before, otheriwise your new symlink will not work

Q. Why not just override it?

The astute among you might ask, if the default python is inside /usr/bin/python why not just override it using?

$ ln -sf /usr/local/bin/python3.8 /usr/bin/python

/usr/bin/ is protected, and it’s bad form to mess around with system prefernces. It’s best not to touch it, /usr/local/bin is yours (the user of the machine) to mess with.

Shebang #!/...

For the most part you will find the pip binary file (thats just plain text by the way) to start like this:

#!/usr/bin/env python

or

#!/usr/local/bin/python3.9

This says, i’m a text file that needs to be ran with the following executable. In the first example, it’s using the system to fin the binary python the same way you would find it in the terminal, see PATH variable above. The second example is a direct path to the binary for the system to use.

Remember pip is a module, the binary pip literaly says this: (this is slighly modified to make it as basic as possible and illustrate a point)

#!/usr/bin/env python
import sys
from pip._internal.cli.main import main
sys.exit(main())
  1. use the python binary
  2. import the sys module to be used later…
  3. import the main function from the pip module
  4. run main, what ever code it returns pass it to sys.exit(..) usually will return 0 but thats neighter here nor there.. just an FYI

1👍

There is no difference typically.

The python -m flag allows you to run a specific module. For example you can run python -m http.server to start a simple server in the current directory.

Python includes a "scripts" directory. Depending on your system setup, modules from the scripts directory can be run directly from the shell without the python -m prefix. For example, typically you run black directly from the shell.

However, there are various reasons you might not want to trust running python modules directly from the shell, including:

  • Running a specific python version. You can do py -3.6 -m pip install something to specify a python version
  • You don’t want to add the scripts folder to your PATH for whatever reason. Maybe because some names conflict with other programs on your computer.

Inside a virtualenv both commands will typically do the same thing, since virtualenv will properly set your PATH

0👍

It’s pretty handy when you need to define which python version you need your package to be installed to (sorry for my bad english).
Say, you have both python3.8 and python3.10.
You can do python3.8 -m pip install django and python3.10 -m pip install django

👤reppon

Leave a comment