Почему нельзя импортировать субмодуль? - PullRequest
0 голосов
/ 20 февраля 2020

Структура моего проекта выглядит следующим образом:

/project
    main.py
    /a_module
        __init__.py
        /sub_module
            __init__.py
            some_file.py

main.py

from a_module import main_api

a_module / __ init __. Py

from sub_module import sub_api

sub_module / __ init __. Py

from some_file import detail_api

In a_module / __ init __. Py дает Unable to import 'sub_module' ошибку.

Почему я не могу импортировать 'sub_module'?

Когда я переключаюсь на относительный путь, решаю ошибку.

from .sub_module import sub_api

Но я не понимаю, __init__.py проектирует для publi c API модуля? Почему бы не рассматривать sub_module как модуль вместо каталога? это такой плохой дизайн для меня ...

1 Ответ

0 голосов
/ 20 февраля 2020

__init__.py выполняется при импорте пакета, который его содержит. Но это не твоя проблема. Ваша проблема в том, что импорт модулей всегда абсолютен, если только явно не является относительным. Это означает, что они должны соединяться из некоторого каталога в sys.path. По умолчанию это включает рабочий каталог, поэтому, когда вы запускаете main.py из project, он может найти a_module и ничего больше.

from sub_module import sub_api

В a_module/__init__.py не работает, хотя потому что импорт всегда абсолютен, если явно не относителен . Таким образом, импорт говорит: «начиная с некоторого sys.path root, найдите пакет верхнего уровня с именем sub_module и импортируйте sub_api из него». Поскольку такого модуля не существует, вы получаете ошибку. from .sub_module import sub_api работает, потому что вы выбрали относительный импорт, поэтому он не начинается заново с sys.path.

Для примера, почему вы это сделаете, я дам вам кое-что, что сломалось в нашем собственном Кодекс за Python 2 дня до абсолютного импорта по умолчанию был законом (from __future__ import absolute_import включил поведение Py3, как мы его исправили, но, несмотря на то, что говорят документы, он никогда не был включен по умолчанию в Py2, только по умолчанию включено поведение относительного импорта). Наш макет был:

 teamnamespace/
               module.py
               math/
                    mathrelatedsubmodule.py
                    othermathsubmodule.py

Теперь, мы невинно подумали, эй, мы поместим все наши пакеты в одно общее пространство имен верхнего уровня, а подпакеты охватывают широкие категории внутри них, и так как у нас было много дополнительные утилиты для основ c математики, мы ставим их под teamnamespace.math. Проблема заключалась в том, что для не -матических модулей, таких как teamnamespace.module, когда они делали:

import math  # or
from math import ceil

, по умолчанию он относительный поиск и импортировал teamnamespace.math как math ( абсолютно бесполезный импорт, поскольку это был только пакет пространства имен, все функции были в подмодулях), а не во встроенном модуле math. Фактически, без поведения Python 3 не было разумного способа получить встроенный модуль math из модуля в teamnamespace. Принимая во внимание, что с поведением Python 3 вы можете получить одно или оба (используя псевдонимы одного или другого с помощью as, без двусмысленности:

# Gets built-in
import math

# Gets teamnamespace.math
from . import math
...