Как я могу прозрачно перенаправить импорт Python? - PullRequest
8 голосов
/ 31 января 2011

Я ищу способ эмулировать символические ссылки для импорта Python.Я хотел бы иметь возможность разархивировать следующую структуру папок без дублирования файлов:

root
├─ python_lib
│  └─ my_utils
│     ├─ __init__.py
│     └─ etc.py
├─ app1
├─ app2
└─ app3
   ├─ lib
   │  ├─ __init__.py
   │  └─ my_utils.py
   └─ run.py

app3/run.py содержит это:

from lib.my_utils import etc

etc.pancakes()

Мне нужен кодиспользовать etc, расположенный в python_lib/my_utils/.Могу ли я что-нибудь добавить в app3/lib/my_utils.py, чтобы Python> = 3.1 прозрачно импортировал папку python_lib/my_utils/ (используя относительные пути и ..), и подпакеты также будут работать?

Ответы [ 6 ]

7 голосов
/ 02 февраля 2011

Вам нужно будет выполнить что-то , прежде чем app3/run.py достигнет оператора импорта.

import python_lib
import sys
sys.modules['lib'] = python_lib
# ...
from lib import etc
print etc.__file__
print dir(etc)
3 голосов
/ 31 января 2011

Вы должны добавить этот путь в sys.path.Например:

lib_path = os.path.abspath( os.path.split( os.getcwd()+"/"+sys.argv[0] )[0]+"/../_lib/my_utils/" )
sys.path.append(lib_path)
1 голос
/ 11 июля 2014

Добавить __init__.py в папку python_lib app3/run.py содержит

import python_lib.my_utils
import os

sys.modules['lib.my_utils'] = python_lib.my_utils
0 голосов
/ 13 ноября 2014

Очень поздно, но это невероятно легко.Все, что вам нужно сделать, это изменить атрибут __path__ вашего пакета, чтобы он указывал на папку, в которой находятся ваши модули.Для этого lib должен быть пакетом, а не просто модулем (т. Е. Папка с __init__.py).По умолчанию __path__ - это список из одного элемента, который содержит путь к папке, в которой находится пакет - ['/path/to/lib'].Это означает, что по умолчанию python выполняет поиск подмодулей в папке модулей (кажется, что это очень логично).

Вы можете изменить содержимое пути так, чтобы оно указывало на то место, где вы хотите, но оно должносодержат абсолютные пути.Если вы только append path/to/lib_python, то python сначала выполнит поиск lib, найдет my_utils.py, а затем остановится.Таким образом, в этом случае вам нужно будет удалить my_utils.py или поместить новый путь перед __path__, чтобы сначала искать местоположение.Это также означает, что папка lib может содержать свои собственные дополнительные модули для общих библиотек и все еще работать.

На практике:

lib / __ init __. Py

from os.path import join
__path__.insert(0, join(__path__[0], "..", "..", "python_lib"))
0 голосов
/ 09 февраля 2013

Как насчет этого? (Да, поставьте его на app3/lib/my_utils.py.)

import os
_f = os.path.realpath(__file__)
_f = os.path.dirname(_f)
_f = os.path.dirname(_f)
_f = os.path.dirname(_f)
_f = os.path.join(_f, 'python_lib')
def f():
    path = sys.path
    path.insert(0, _f)
    sys.modules['lib.my_utils'] = __import__('my_utils')
    path.pop(0)
f()
0 голосов
/ 26 февраля 2012

Я внес следующие изменения в вашу структуру каталогов, чтобы упростить пример:

  • создать root / python_lib / __ init __. Py
  • переименовать root / python_lib в root / lib
  • заменить root / app3 / lib / на lib.py

Поместите следующий код в root / app3 / lib.py

import os
import sys

pth = os.path.sep.join(sys.argv[0].split(os.path.sep)[0:-2])
sys.path.insert(0, pth)
del sys.modules[__name__]
import lib

По сути, у нас есть фиктивный модуль, который заменяет собственную ссылку в sys.modules ссылкой на модуль или пакет в другом месте.

...