Конфликт имен между модулями, импортированными в сторонние модули
Предположим, что mine.py хочет импортировать moduleA и moduleB, но moduleA и moduleB каждый пытается импортировать модуль с именем "moduleC". Это два разных модуля, которые оба названы "moduleC". Когда выполняется mine.py, в зависимости от sys.path, либо moduleA, либо moduleB получает правильный "moduleC", другой получает сюрприз, и наступает хаос.
Если moduleA и moduleB были написаны разными авторами, ни один из которых не является нами, предпочтительно не изменять эти модули. Есть ли какое-либо решение для автора mine.py, которое не изменяет модуль A или модуль B?
Следующие вопросы спрашивают, как решить эту проблему, когда вы являетесь автором модуля A или moduleB.
Импорт из встроенной библиотеки, когда существует модуль с таким же именем
Мой конкретный случай
Я хочу запустить программу под названием PyMOL под отладчиком Python, pdb. У PyMOL, к сожалению, есть "cmd.py", который он импортирует и который конфликтует с обычным cmd, который импортирует pdb.
Соответствующие части установки PyMOL выглядят так:
pymol/
__init__.py
cmd.py
PyMOL запускается путем выполнения __init__.py
, Этот файл затем импортирует cmd
как from pymol import cmd
,
Работая от того, что указал BrenBarn, пока я могу получить pdb
успешно импортировать правильный cmd
временно удалив pymol
каталог с фронта sys.path
, После этого, когда PyMOL пытается импортировать его cmd
это падает. Каким-то образом мне нужно удалить Python cmd
из модуля импорта поиска до PyMOL
импорт, но после pdb
импорт.
Минимальный пример
$ ls
pymol/
$ ls pymol/
__init__.py cmd.py
init.py
# insert some code into __init__.py directly
import sys
pymol_path = sys.path[0]
sys.path[0] = ""
import pdb
sys.path[0] = pymol_path
from pymol import cmd
# test a sandwich of calls that require each "cmd" modules
pdb.set_trace()
cmd.foo()
pdb.set_trace()
cmd.foo()
print "done!"
# original PyMOL __init__.py code would follow
cmd.py
def foo():
print("cmd.foo()")
Попытайся
$ PYTHONPATH= python ./pymol/__init__.py
> /Users/khouli/scr/pymol_scr/pymol/__init__.py(11)<module>()
-> cmd.foo()
(Pdb) continue
cmd.foo()
> /Users/khouli/scr/pymol_scr/pymol/__init__.py(13)<module>()
-> cmd.foo()
(Pdb) continue
cmd.foo()
done!
Изменить: метод, приведенный выше, теперь, кажется, работает, но, как говорится в ответе BrenBarn, вероятно, нет решения, которое оставило бы весь сторонний код неизменным, как первоначально задавался вопрос. Это связано с причудами в PyMOL.
1 ответ
Ваша проблема не только в импорте, но и в том, что вы работаете __init__.py
как сценарий. Когда вы запускаете скрипт, Python добавляет каталог, содержащий скрипт, в начало sys.path
и это глобально влияет на весь последующий импорт.
Невозможно что-либо настроить, если вы запускаете файл, который не хотите изменять. Вы не можете сделать подлый sys.path
манипуляциями, если вы сначала не запустите свой собственный код, чтобы установить путь так, как вы этого хотите. Если вы импортируете файл вместо его запуска, у вас есть возможность использовать свой собственный код для настройки путей.
Я подозреваю, что эта проблема в некоторой степени специфична для PyMOL, которая, к сожалению, не очень хорошо разработана в этом отношении. Глядя на исходный код здесь, я вижу, что PyMOL __init__.py
включает в себя много пользовательского кода, который делает странные вещи, такие как import __main__
и проверка, имеет ли версия, которая работает, имеет различные атрибуты. Вы можете попробовать использовать "неподдерживаемый / экспериментальный" метод, описанный в комментариях к этому файлу, который включает импорт PyMOL вместо его запуска. Я ничего не знаю о PyMOL, поэтому я не знаю, как это будет работать.
Возможно, стоит связаться с авторами PyMOL, чтобы предложить исправить это.