Могут ли модули с общей иерархией пакетов упомянуты несколько раз в моей PYTHONPATH? - PullRequest
5 голосов
/ 25 августа 2011

У меня есть два отдельных проекта с общим именем пакета.Они работают нормально, пока они не оба на 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 для импорта foo, тогда он будет работать.Но я хочу знать, возможно ли это сделать без изменения одного из пакетов.

Ответы [ 2 ]

3 голосов
/ 28 января 2012

Хотя механизм импорта не поддерживается изначально, существует обходное решение для создания пакетов с именами в 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 и обладает тем преимуществом, что также обрабатывает пакеты, содержащиеся в файлах egg zip.

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

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

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

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

3 голосов
/ 25 августа 2011

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

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

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

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

...