Пути python и порядок импорта

Хорошо, поэтому я действительно хочу получить это правильно, потому что я постоянно сталкиваюсь с этим при создании больших пакетов py2app/py2exe. Поэтому у меня есть пакет, содержащий множество модулей/пакетов, которые также могут быть в пакетах сайтов/по умолчанию для пользователей (если у пользователя есть дистрибутив python), но я хочу, чтобы мои распределенные пакеты вступили в силу перед ними при запуске из моего дистрибутива,

Теперь из того, что я прочитал здесь PYTHONPATH должен быть первым, что добавлено в sys.path после но из того, что я тестировал на своей машине, это не так, и все папки, определенные в $site-packages$/easy-install.pth, имеют приоритет над этим.

Так может кто-то, пожалуйста, дайте мне более подробное объяснение об этом порядке импорта.//Помогите мне найти способ установить переменные среды таким образом, чтобы распространенные мной пакеты имели приоритет над установленными по умолчанию. Пока моя попытка, например, на Mac OS OS py2app, в моей точке входа script:

 os.environ['PYTHONPATH'] = DATA_PATH + ':'
 os.environ['PYTHONPATH'] = os.environ['PYTHONPATH'] + os.path.join(DATA_PATH
                                                            , 'lib') + ':'
 os.environ['PYTHONPATH'] = os.environ['PYTHONPATH'] + os.path.join(
                                DATA_PATH, 'lib', 'python2.7', 'site-packages') + ':'
 os.environ['PYTHONPATH'] = os.environ['PYTHONPATH'] + os.path.join(
                          DATA_PATH, 'lib', 'python2.7', 'site-packages.zip')

Это в основном структура пакета, созданного py2app. Тогда я просто:

 SERVER = subprocess.Popen([PYTHON_EXE_PATH, '-m', 'bin.rpserver'
                            , cfg.RPC_SERVER_IP, cfg.RPC_SERVER_PORT],
                            shell=False, stdin=IN_FILE, stdout=OUT_FILE, 
                            stderr=ERR_FILE)

Здесь PYTHON_EXE_PATH - это путь к exe python, который добавляется py2app в пакет. Теперь это отлично работает на машине, на которой нет установленного python. Однако, когда дистрибутив python уже присутствует, их пакеты-сайты имеют приоритет.

Ответы

Ответ 1

Python ищет пути в sys.path по порядку (см. http://docs.python.org/tutorial/modules.html#the-module-search-path). easy_install изменяет этот список напрямую (см. последнюю строку в файле easy-install.pth):

import sys; new=sys.path[sys.__plen:]; del sys.path[sys.__plen:]; p=getattr(sys,'__egginsert',0); sys.path[p:p]=new; sys.__egginsert = p+len(new)

Это в основном принимает все каталоги и добавляет их в начало списка.

Также см. Яйца в пути до переменной среды PYTHONPATH.

Ответ 2

Эта страница является хорошим результатом Google для "Порядка импорта Python", поэтому здесь, надеюсь, более четкое объяснение:

Как объясняют обе эти страницы, порядок import:

  1. Встроенные модули Python.
  2. sys.path записи.
  3. Зависящие от установки местоположения по умолчанию.

Как объясняется на странице документа sys.path, она заполняется следующим образом:

  1. Первая запись - это полный путь к каталогу файла, с которого python был запущен (поэтому /someplace/on/disk/> $ python /path/to/the/run.py означает, что первый путь - /path/to/the/, и аналогично, если вы находитесь в /path/to/> $ python the/run.py (он все еще ВСЕГДА собирается быть установленным в ПОЛНЫЙ ПУТЬ к каталогу)), или это будет пустая строка, если python был запущен без файла или интерактивного режима (пустая строка означает "текущий рабочий каталог для процесса python"). Другими словами, Python предполагает, что файл, который вы запустили, хочет иметь возможность относительного импорта модулей package/-folders и blah.py, которые существуют в том же месте, что и файл, с которым вы запустили python.
  2. Другие записи в sys.path заполняются из переменной окружения PYTHONPATH. В основном ваши глобальные папки pip.

Итак, в основном: да, вы можете верить, что Python сначала найдет ваши локальные папки-пакеты и файлы модулей, прежде чем что-либо устанавливать в глобальном масштабе.

Вот пример, чтобы объяснить дальше:

myproject/ # <-- This is not a package (no __init__.py file).
  modules/ # <-- This is a package (has an __init__.py file).
    __init__.py
    foo.py
  run.py
  second.py

executed with: python /path/to/the/run.py
will cause sys.path[0] to be "/path/to/the/"

run.py contents:
import modules.foo as foo # will import "/path/to/the/" + "modules/foo.py"
import second # will import "/path/to/the/" + "second.py"

second.py contents:
import modules.foo as foo # will import "/path/to/the/" + "modules/foo.py"