Разница между 'python -m pip install <package-name>' и 'pip install <package-name>'

Я столкнулся с проблемой, когда я пытаюсь запустить приложение Django в виртуальной среде, но оно продолжает показывать мне ошибки об отсутствующих пакетах, которые необходимо установить, хотя я установил их ранее, используя pip install <package-name>.

Проблемы не могли быть решены, пока я не использовал python -m pip install <package-name> для установки недостающих пакетов.

Мой вопрос в том, в чем разница между этими двумя командами? Одна из команд устанавливает пакеты в виртуальную среду, а другая делает это глобально? Я запутался.

Примечание: Также при запуске pip freeze показывает другие установленные пакеты, чем при запуске python -m pip freeze.

Обновление:

Запуск pip list -v показывает, что пакеты, установленные с помощью pip install <package-name>, находятся внутри виртуальной среды в каталоге lib/python3.8/site-packages, а запуск python -m pip list -v показывает, что пакеты, установленные с помощью python -m pip <package-name>, находятся в каталоге /usr/lib/<python3 or python3.8>/<site-packages or dist-packages>.

Обычно разницы нет.

Флаг python -m позволяет запустить определенный модуль. Например, вы можете выполнить python -m http.server для запуска простого сервера в текущем каталоге.

Python включает каталог "scripts". В зависимости от настроек вашей системы, модули из каталога scripts могут быть запущены непосредственно из оболочки без префикса python -m. Например, обычно вы запускаете black непосредственно из оболочки.

Однако существуют различные причины, по которым вы можете не доверять запуск модулей python непосредственно из оболочки, включая:

  • Запуск определенной версии python. Вы можете сделать py -3.6 -m pip install something, чтобы указать версию python
  • .
  • По какой-то причине вы не хотите добавлять папку scripts в PATH. Возможно, потому что некоторые имена конфликтуют с другими программами на вашем компьютере.

Внутри virtualenv обе команды обычно делают одно и то же, поскольку virtualenv правильно установит ваш PATH

Добро пожаловать в мир симлинков, бинарной открываемости с помощью PATH, и shebang #!/... (*nix).

Прежде чем вникнуть в суть всего этого, давайте поговорим о том, что такое pip:

pip является одновременно модулем python (т.е. python -m pip (подразумевается модуль -m)) и бинарным $ pip. pip как двоичный файл (программа) является опциональным, он не обязателен. pip как модуль (внутри site-packages, где установлены все модули python) АБСОЛЮТНО необходим! Без него ничего не будет работать, или, что еще хуже, вы будете использовать модуль pip из другой версии python, которая у вас установлена, и тогда вы действительно будете биться головой об стену...

Переменная PATH

echo $PATH (*nix) покажет вам что-то вроде этого:

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

Это означает, что система через терминал будет искать двоичные файлы сначала внутри /usr/local/bin потом /usr/bin потом ... и так далее. Если она нашла его в первом попавшемся месте, отлично, дело сделано, не нужно продолжать поиск. Вы можете иметь одинаковые двоичные имена в разных каталогах, важен порядок PATH, второй никогда не будет выполнен, НИКОГДА.

Почему я упоминаю об этом? Допустим, вы установили несколько версий python или pip, и вы установили их в неправильном месте? В неправильном порядке? Ну, этот бинарник не будет работать так, как ожидалось.

Симлинки

У вас могут быть разные версии pip и python - они независимы друг от друга, то есть, если вы используете python с версией 3.8, это не значит, что ваш pip указывает на тот же двоичный файл python.

Быстрый способ проверки заключается в следующем: (это относится к 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

Вы можете видеть, что он использует системную версию python и все другие версии, которые у меня есть, игнорируются, если я просто запускаю python, я могу "исправить" это, указав номер версии, например python3.8...

Вы можете исправить это, сначала выяснив, какие двоичные файлы вам доступны:

$ 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

Допустим, я хочу, чтобы по умолчанию python было python3.8, тогда делаем:

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

hash -r указывает терминалу забыть все найденные ранее банары, иначе ваша новая симлинка не будет работать

Q. Почему бы просто не отменить его?

Проницательные из вас могут спросить, если python по умолчанию находится внутри /usr/bin/python, почему бы просто не переопределить его с помощью

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

/usr/bin/ защищен, и нехорошо вмешиваться в системные предпочтения. Лучше не трогать его, /usr/local/bin - это ваше (пользователя машины) дело.

Шебанг #!/...

В большинстве случаев двоичный файл pip (который, кстати, является обычным текстом) начинается так:

#!/usr/bin/env python

или

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

Это говорит, что я текстовый файл, который нужно запустить с помощью следующего исполняемого файла. В первом примере используется система для поиска двоичного файла python таким же образом, как вы нашли бы его в терминале, см. выше переменную PATH. Второй пример - это прямой путь к двоичному файлу для использования системой.

Помните, что pip - это модуль, бинарный pip буквально говорит следующее: (это слегка изменено, чтобы сделать его как можно более простым и проиллюстрировать суть)

#!/usr/bin/env python
import sys
from pip._internal.cli.main import main
sys.exit(main())
  1. используйте двоичный код python
  2. импортируйте модуль sys, который будет использоваться позже...
  3. импортируйте функцию main из модуля pip
  4. .
  5. запустите main, какой бы код она не вернула, передайте его sys.exit(..) обычно возвращается 0 но это не важно... просто к сведению

Это довольно удобно, когда вам нужно определить, к какой версии python должен быть установлен ваш пакет (извините за мой плохой английский). Скажем, у вас есть python3.8 и python3.10. Вы можете сделать python3.8 -m pip install django и python3.10 -m pip install django

Вернуться на верх