__Init__.py не требуется для пакетов в Python 3.3+


195

Я использую Python 3.5.1. Я прочитал документ и раздел пакета здесь: https://docs.python.org/3/tutorial/modules.html#packages

Теперь у меня есть следующая структура:

/home/wujek/Playground/a/b/module.py

module.py:

class Foo:
    def __init__(self):
        print('initializing Foo')

Теперь пока в /home/wujek/Playground:

~/Playground $ python3
>>> import a.b.module
>>> a.b.module.Foo()
initializing Foo
<a.b.module.Foo object at 0x100a8f0b8>

Точно так же сейчас в доме, супер-папка из Playground:

~ $ PYTHONPATH=Playground python3
>>> import a.b.module
>>> a.b.module.Foo()
initializing Foo
<a.b.module.Foo object at 0x10a5fee10>

На самом деле, я могу делать разные вещи:

~ $ PYTHONPATH=Playground python3
>>> import a
>>> import a.b
>>> import Playground.a.b

Почему это работает? Я хотя нужно быть __init__.pyфайлы (пустые будет работать) в обоих aи bдля , module.pyчтобы быть ввозу , когда Python путь указывает на Playgroundпапку?

Похоже, это изменилось с Python 2.7:

~ $ PYTHONPATH=Playground python
>>> import a
ImportError: No module named a
>>> import a.b
ImportError: No module named a.b
>>> import a.b.module
ImportError: No module named a.b.module

С __init__.pyобоими ~/Playground/aи ~/Playground/a/bвсе работает нормально.

Ответы:


192

В Python 3.3+ есть неявные пакеты пространства имен, которые позволяют создавать пакеты без __init__.pyфайла.

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

Старый способ с __init__.pyфайлами все еще работает как в Python 2.


10
Я прочитаю документ, но он немного длинный. Можно ли быстро подвести итоги? Не могли бы вы сказать мне: он все еще поддерживает init .py или полностью игнорирует их? Если это действительно поддерживает их, в чем разница в функциональности и почему эта двойственность?
wujek

3
Так что учебник, вероятно, должен быть обновлен. Открыта ли для этого ошибка документации?
Мишель Самия

4
Я все еще расстроен, что это не поддается Zen Of Python строке 2: Explicit is better than implicit.....
JayRizzo

5
@JayRizzo Но: «Хотя практичность превосходит чистоту».
Майк Мюллер

19
@JayRizzo IMO это еще более явно. Иногда случается, что вы делаете инициализацию __init__.py, иногда нет. В Python 3, когда мне нужны эти вещи, я создаю новый __init__.pyс конкретным кодом, в противном случае я не делаю. Это полезно знать, визуально, какие пакеты имеют пользовательский init. Вместо этого в Python 2 мне всегда нужно помещать __init__.py(часто пустой), делая их много, и, наконец, сложнее запомнить, где вы поместили свой код инициализации. Это также должно соответствовать «Должен быть один - и желательно только один - очевидный способ сделать это».
Паоло

148

ВАЖНЫЙ

@ Ответ Майка правильный, но слишком неточный. Это правда, что Python 3.3+ поддерживает неявные пакеты пространства имен, что позволяет создавать пакеты без __init__.pyфайла.

Это, однако, относится ТОЛЬКО к ПУСТЫМ__init__.py файлам. Таким образом, файлы EMPTY__init__.py больше не нужны и могут быть опущены. Если вы хотите запустить определенный сценарий инициализации при импорте пакета или любого из его модулей или подпакетов, вам все равно требуется __init__.pyфайл. Это отличный ответ на переполнение стека, объясняющий, почему вы захотите использовать __init__.pyфайл для дальнейшей инициализации, если вам интересно, почему это в любом случае полезно.

Пример структуры каталогов:

  parent_package/
     __init__.py            <- EMPTY, NOT NECESSARY in Python 3.3+
     child_package/
          __init__.py       <- STILL REQUIRED if you want to run an initialization script
          child1.py
          child2.py
          child3.py

parent_package/child_package/__init__.py:

print("from parent")

ПРИМЕРЫ

Приведенные ниже примеры демонстрируют, как выполняется скрипт инициализации при child_packageимпорте одного или одного из его модулей.

Пример 1 :

from parent_package import child_package  # prints "from parent"

Пример 2 :

from parent_package.child_package import child1  # prints "from parent"

2
Предположим, у меня есть run_script.pyтот же каталог, что parent_packageи у меня, но я могу импортировать как from parent_package.child_package import child1без __init__.py?
mrgloom

Является ли цель этого, чтобы вы могли написать child_package.some_function, даже если some_function определена в childX.py? Другими словами, он не требует от пользователя знать о разных файлах в child_package? ?
Джонбейкерс

Да, я не понимаю, зачем ты это сделал child1.py, child2.pyвместо того , чтобы просто собрать их код в __init__.py напрямую.
Бинки

Не следует ли операторы импорта в __init__быть относительный импорт , то есть from . import child1? Абсолютный импорт дает мне ModuleNotFoundError(в Python 3.6)
Halbeard

5
По моему опыту, даже с python 3.3+ __init__.pyиногда все еще требуется пустое место , например, когда вы хотите сослаться на подпапку как на пакет. Например, если я запустил python -m test.fooего, он не работал, пока я не создал пустую __init__.pyпапку в тестовой папке. И я говорю о версии 3.6.6 здесь!
Прахлад Ери

7

Если у вас есть setup.pyв вашем проекте, и вы используете find_packages()в нем, необходимо иметь __init__.pyфайл в каждом каталоге для автоматического поиска пакетов.

Пакеты распознаются, только если они содержат __init__.pyфайл

UPD : если вы хотите использовать неявные пакеты пространства имен без использования __init__.py, просто используйте find_namespace_packages()вместо этого

Документы


2

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.