Подтвердить что ты не робот

Почему "импортировать модуль", а затем "из модуля импорта пакетов" загружает модуль снова?

У меня есть пакет в PYTHONPATH, который выглядит примерно так:

package/
    __init__.py
    module.py
        print 'Loading module'

Если я запускаю Python из каталога package/ (или записываю другой модуль в этот каталог) и набираю

import module

загружает module.py и выводит "Загрузочный модуль", как и ожидалось. Однако, если я тогда набираю

from package import module

он загружает module.py и снова печатает "Загрузочный модуль", чего я не ожидаю. Какое обоснование для этого?

Примечание. Я понимаю, что я понимаю, почему Python делает это, потому что ключ sys.modules для import module - это просто "module", но для from package import module it "package.module". Поэтому я предполагаю, что я хочу знать, почему ключ здесь различен - почему не имя пути к файлу, используемое в качестве ключа, так что Python делает то, что вы ожидаете здесь?

4b9b3361

Ответ 1

Фактически, запустив код из каталога package, вы неправильно сконфигурировали Python. Вы не должны помещать этот каталог в sys.path, так как он внутри пакета.

Python не использует имя файла в качестве ключа, потому что он не импортирует файл, а импортирует модуль. Предоставление людям возможности "import c:\jim\my files\projects\code\stuff" поощряло бы все виды гадости.

Рассмотрим этот случай: что, если вы были в ~/foo/package/ и ~/bar, были на PYTHONPATH - но ~/bar просто символическая ссылка на ~/foo? Ожидаете ли вы, что Python решит, а затем дедуплицируйте символическую ссылку для вас? Что, если вы поместите относительный каталог в PYTHONPATH, а затем смените каталоги? Что, если "foo.py" является символической ссылкой на "bar.py"? Вы ожидаете, что и те, и другие будут дедуплицированы? Что, если они не символические ссылки, а просто точные копии? Добавление сложных правил, чтобы попытаться сделать что-то удобное в двусмысленных обстоятельствах, означает, что он делает что-то очень неудобное для других людей. (Python zen 12: перед лицом двусмысленности откажитесь от соблазна угадать.)

Python делает здесь что-то простое, и ваша ответственность - убедиться, что среда настроена правильно. Теперь вы можете утверждать, что по умолчанию это не очень хорошая идея поместить текущий каталог на PYTHONPATH - я мог бы даже согласиться с вами - но учитывая, что он есть, он должен следовать тому же согласованному набору правил, что и другой путь записи делают. Если он предназначен для запуска из произвольного каталога, ваше приложение всегда может удалить текущий каталог из sys.path, начиная с sys.path.remove('').

Ответ 2

Это незначительный дефект текущей системы модулей.

При импорте модуля вы делаете это из текущего пространства имен, у которого нет имени. значения внутри этого пространства имен те же, что и в пакете, но интерпретатор не может этого знать.

При импорте package.module вы импортируете модуль из пространства имен пакетов.

Это причина, по которой main.py должен находиться вне пакета forlder. Многие модули имеют эту организацию:

package /
    main.py
    package /
        sub_package1/
        sub_package2/
        sub_package3/
        module1.py
        module2.py

Вызывая только main.py, убедитесь, что пространства имен правильно установлены, aka текущее пространство имен - это main.py's. Это делает невозможным вызов import module1.py в module2.py. Вам нужно вызвать import package.module1. Делает вещи более простыми и однородными.

И да, импортируйте текущую папку, поскольку текущая безымянная папка была плохой идеей. Это PITA, если вы выходите за рамки нескольких сценариев. Но поскольку Python начал там, это было не совсем бессмысленно.