импорта модулей и __init__.py в Python

Я пытаюсь понять, что лучше всего относится к механике импорта Python (v2.7). У меня есть проект, который начал расти немного и позволяет сказать, что мой код организован следующим образом:

foo/ __init__.py Foo.py module1.py module2.py module3.py 

Имя пакета – foo а под ним есть модуль Foo.py который содержит код для класса Foo . Поэтому я использую одно и то же имя для пакета, модуля и класса, которые могут быть не очень умными для начала.

__init__.py пуст, и класс Foo требует импорта module1, module2 and module3 поэтому часть моего файла Foo.py выглядит так:

 # foo/Foo.py import module1 import module2 import module3 class Foo(object): def __init__(self): .... .... if __name__ == '__main__': foo_obj = Foo() 

Однако позже я пересмотрел это, и я подумал, что было бы лучше иметь весь импорт в файле __init__.py . Следовательно, моя __init__.py теперь выглядит так:

 # foo/__init__.py import Foo import module1 import module2 import module3 .... .... 

и мой Foo.py нужно импортировать foo :

 # foo/Foo.py import foo 

Хотя это выглядит удобно, так как это один лайнер, я немного обеспокоен тем, что он может создавать круговой импорт. Я имею в виду, что при Foo.py скрипта Foo.py он будет импортировать все, что может, а затем __init__.py , который снова импортирует Foo.py (это правильно?). Кроме того, использование одного и того же имени для пакета, модуля и класса делает вещи более запутанными.

Имеет ли смысл то, как я это сделал? Или я прошу о неприятностях?

  • Получить последнее исключение в pdb
  • поиск дубликатов в списке списков
  • Когда и как использовать RLock Python
  • Модуль Python для поиска патентных баз данных, то есть USPTO или EPO
  • Как определить, содержит ли 2-мерный список значение?
  • Вызов, если __name__ == '__main__': в одном модуле от функции в другом модуле
  • Как организовать проект python, который содержит несколько пакетов, чтобы каждый файл в пакете можно было запускать отдельно?
  • Перечисление списков в списке в Python
  • 4 Solutions collect form web for “импорта модулей и __init__.py в Python”

    Несколько вещей, которые вы могли бы сделать, чтобы улучшить свою организацию, если только придерживаться некоторых популярных конвенций и стандартов python.

    Если вы будете искать эту тему, вы неизбежно столкнетесь с людьми, рекомендующими рекомендации PEP8 . Это фактические канонические стандарты для организации кода python.

    Модули должны иметь короткие имена с прописными буквами. Подчеркивания могут использоваться в имени модуля, если это улучшает читаемость. Пакеты Python также должны иметь короткие имена всех строчных букв, хотя использование подчеркиваний не рекомендуется.

    На основе этих рекомендаций вы должны называть и проектировать модули проекта следующим образом:

     foo/ __init__.py foo.py module1.py module2.py module3.py 

    Я считаю, что обычно лучше избегать импорта модулей без необходимости в __init__.py если вы не делаете это по причинам пространства имен. Например, если вы хотите, чтобы пространство имен для вашего пакета выглядело так

     from foo import Foo 

    вместо

     from foo.foo import Foo 

    Тогда имеет смысл поставить

     from .foo import Foo 

    в вашем __init__.py . Поскольку ваш пакет становится больше, некоторые пользователи могут не захотеть использовать все подпакеты и модули, поэтому не имеет смысла заставить пользователя ждать загрузки всех этих модулей, неявно импортируя их в ваш __init__.py , Кроме того, вы должны учитывать, хотите ли вы, чтобы module1 , module2 и module3 частью вашего внешнего API. Используются ли они только Foo и не предназначены для конечных пользователей? Если они используются только внутренне, то не включайте их в __init__.py

    Я бы также рекомендовал использовать абсолютный или явный относительный импорт для импорта подмодулей. Например, в foo.py

    абсолют

     from foo import module1 from foo import module2 from foo import module3 

    Явный относительный

     from . import module1 from . import module2 from . import module3 

    Это предотвратит любые возможные проблемы с именами с другими пакетами и модулями. Это также упростит, если вы решите поддерживать Python3, поскольку неявный относительный синтаксис импорта, который вы используете в настоящее время, не поддерживается в Python3.

    Кроме того, файлы внутри вашего пакета обычно не должны содержать

     if __name__ == '__main__' 

    Это связано с тем, что запуск файла в качестве скрипта означает, что он не будет считаться частью пакета, к которому он принадлежит, поэтому он не сможет сделать относительный импорт.

    Лучший способ предоставить исполняемые скрипты пользователям – это использовать scripts или функции console_scripts для setuptools . Способ организации ваших сценариев может быть разным в зависимости от того, какой метод вы используете, но я обычно организую такие как:

     foo/ __init__.py foo.py ... scripts/ foo_script.py setup.py 

    Согласно PEP 0008, «Общественные и внутренние интерфейсы» :

    Импортированные имена всегда должны рассматриваться как детализация реализации. Другие модули не должны полагаться на косвенный доступ к таким импортированным именам, если они не являются явно документированной частью API-модуля содержащего модуля, например os.path или модуля __init__ пакета, который предоставляет функции из подмодулей.

    Таким образом, это может означать, что в модуле __init__ можно импортировать импорт, если __init__ используется для отображения функций из подмодулей. Вот короткое сообщение в блоге, которое я нашел с несколькими примерами использования Pythonic __init__ , используя импорт, чтобы сделать подпакеты доступными на уровне пакета.

    Ваш пример перемещения операторов импорта в __init__ , чтобы иметь только один импорт в Foo , похоже, не соответствует этому правилу. Моя интерпретация заключается в том, что импорт в ваш __init__ должен использоваться для внешних интерфейсов, иначе просто поместите свои операторы импорта в необходимый им файл. Это сэкономит вам проблемы при изменении имен подмодулей и избавит вас от ненужного или труднодоступного импорта, когда вы добавляете больше файлов, в которых используется другое подмножество подмодулей.

    Что касается круговых ссылок, это, безусловно, возможно в Python ( например ). Я писал об этом, прежде чем я попробовал свой пример с игрушкой, но чтобы сделать пример работы, мне пришлось переместить Foo.py на уровень, например:

     Foo.py foo/ __init__.py module1.py module2.py module3.py 

    С помощью этой установки и некоторых операторов печати запуск python Foo.py дает результат:

     module 1 module 2 module 3 hello Foo constructor 

    и выходит нормально. Обратите внимание, что это связано с добавлением if __name__ == "__main__" – если вы добавите оператор печати за пределы этого, вы увидите, что Python по-прежнему загружает модуль дважды. Лучшим решением было бы удалить импорт из вашего __init__.py . Как я сказал ранее, это может быть или не иметь смысла, в зависимости от того, что такое подмодули.

    Вы можете обратиться к «Руководству по стилю для кода Python» для лучших практик, импорт хранится в классе в этом руководстве.

    https://www.python.org/dev/peps/pep-0008/#imports

    Я не могу сказать окончательно, если это правильный путь, но я всегда делал это по-прежнему. То есть, я всегда сохранял init .py пустым и просто импортировал вещи в Foo.py по мере необходимости.

    Из того, как вы это описываете, похоже, что в последней форме происходит круговая логика.

    Python - лучший язык программирования в мире.