Чи не потрібен __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(часто порожній), роблячи велику кількість їх і нарешті важче запам'ятати, де ви розмістили свій код init. Це також повинно відповідати "Має бути один-- і бажано лише один - очевидний спосіб зробити це".
Паоло

148

ВАЖЛИВО

@ Відповідь Майка правильна, але занадто неточна. Це правда, що Python 3.3+ підтримує непрямі пакети просторів імен, що дозволяє йому створювати пакет без __init__.pyфайлу.

Це, однак, застосовується ТОЛЬКО__init__.py до файлів EMPTY . Отже файли 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?
мрглоом

Чи є мета цього, щоб ви могли записати child_package.some_function, навіть якщо деяка функція визначена у childX.py? Іншими словами, це дозволяє уникнути того, щоб користувач вимагав знати про різні файли у child_package? ?
johnbakers

Так, я не розумію, чому ви б це зробили 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()замість

Документи


1

Я б сказав, що слід опустити __init__.pyєдиний, якщо хочеться мати пакет неявного простору імен . Якщо ви не знаєте, що це означає, ви, мабуть, цього не хочете, і тому вам слід продовжувати використовувати __init__.pyнавіть у Python 3.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.