Могут ли модули с общей иерархией пакетов упоминаться несколько раз в моем PYTHONPATH?

У меня есть два отдельных проекта с общим именем пакета. Они работают нормально, пока они оба не находятся в PYTHONPATH, но как только они оба появляются, один из них не может найти импорт в своем собственном проекте.

Пример, два таких проекта:

Проект 1:

x/
  __init__.py
  test.py
  foo.py

test.py содержит строку:

import x.foo

Проект 2:

x/
  __init__.py
  bar.py

Если я побегу

PYTHONPATH=. python x/y/test.py

ошибки нет. Но если я побегу

PYTHONPATH='pathtoproject2:.' python x/test.py

Я получаю сообщение об ошибке:

Traceback (most recent call last):
  File "x/test.py", line 1, in <module>
    import x.foo
ImportError: No module named foo

Есть ли способ, чтобы разные проекты Python с общим пакетом использовали PYTHONPATH? Или Python всегда будет использовать только первый путь, по которому найден пакет?

Примечание. Я знаю, что если вы измените импорт из x.foo на import foo, тогда он будет работать. Но я хочу знать, можно ли это сделать без изменения любого пакета.


person Simonz    schedule 25.08.2011    source источник


Ответы (2)


Хотя изначально механизм импорта не поддерживается, существует обходное решение для создания пакетов с именами в python. Вам просто нужно поместить следующий код в оба файла __init__.py.

try:
    import pkg_resources
    pkg_resources.declare_namespace(__name__)
except ImportError:
    import pkgutil
    __path__ = pkgutil.extend_path(__path__, __name__)

pkg_resources предоставляется пакетом setuptools python и имеет то преимущество, что также обрабатывает пакеты, содержащиеся в zip-файлах яйца.

pkgutil содержится в стандартной библиотеке Python, поэтому мы полагаемся на него для обработки расширения пространства имен, если setuptools не установлен в системе.

дополнительную информацию о пакетах пространства имен python можно найти здесь:

http://packages.python.org/distribute/setuptools.html#namespace-packages

http://www.python.org/dev/peps/pep-0382/

person vinilios    schedule 27.01.2012

В настоящее время Python не поддерживает пакеты из разных каталогов. Пакет — это единица, а не просто пространство имен. Это отличается от «пакетов» Java или более подходящих «пространств имен» в .NET.

При импорте пакета Python будет сканировать sys.path последовательно и использовать первое совпадение. Если в каталоге, который появляется позже в пути, есть другой модуль или пакет с совпадающим именем, он не будет найден.

Ваша "заметка" не соответствует действительности, кстати. Когда вы используете import foo, Python попытается выполнить относительный импорт в каталоге test.py, не найдет совпадений, затем попытается выполнить абсолютный импорт модуля foo, которого также не существует, а затем создаст ImportError.

Вместо того, чтобы использовать имена пакетов для группировки модулей с использованием общего префикса, думайте о пакетах как о небольших автономных библиотеках. В Python плоская структура лучше, чем вложенная, и предпочтительнее иметь несколько пакетов верхнего уровня, каждый из которых выполняет одну определенную задачу, чем иметь один большой монолитный пакет. Вместо org.example.foo и org.example.bar просто используйте foo и bar.

person Ferdinand Beyer    schedule 25.08.2011
comment
+1 Кажется, что, хотя это и возможно, как объяснено в другом ответе, это не путь Python... - person z7sg Ѫ; 19.03.2012