Відповіді:
Він раніше був обов'язковою частиною пакету ( старий, попередній 3.3 "звичайний пакет" , а не новіший 3.3+ "пакет простору імен" ).
Python визначає два типи пакунків, звичайні пакети та пакети простору імен. Звичайні пакети - це традиційні пакунки, як вони існували в Python 3.2 та новіших версіях. Звичайний пакет зазвичай реалізується у вигляді каталогу, що містить
__init__.py
файл. Коли імпортується звичайний пакет, цей__init__.py
файл неявно виконується, а об'єкти, які він визначає, пов'язані з іменами в просторі імен пакету.__init__.py
Файл може містити один і той же код Python , що будь-який інший модуль може містити, і Python буде додати деякі додаткові атрибути модуля , коли він імпортується.
Але просто натисніть посилання, воно містить приклад, більше інформації та пояснення пакетів простору імен, без виду пакунків __init__.py
.
sys.path.insert(0, '/path/to/datetime')
, замінивши цей шлях на шлях до каталогу, який ви щойно створили. Тепер спробуйте щось на кшталт from datetime import datetime;datetime.now()
. Ви повинні отримати AttributeError (оскільки він імпортує ваш порожній файл зараз). Якби ви повторили ці кроки, не створюючи порожній файл init, цього не сталося. Ось що призначено запобігти.
from datetime import datetime
без помилок. Це добре ще до версії 2.3!
builtins
перераховує вбудовані функції та класи , а не вбудовані модулі (див. Docs.python.org/3/tutorial/modules.html#the-dir-function ). Якщо ви хочете перерахувати вбудовані модулі , зробіть це import sys; print(sys.builtin_module_names)
(див. Docs.python.org/3/library/sys.html#sys.builtin_module_names ).
Названі файли __init__.py
використовуються для позначення каталогів на диску як каталогі пакетів Python. Якщо у вас є файли
mydir/spam/__init__.py
mydir/spam/module.py
і mydir
на вашому шляху, ви можете імпортувати код в module.py
якості
import spam.module
або
from spam import module
Якщо ви вилучите __init__.py
файл, Python більше не буде шукати підмодулі всередині цього каталогу, тому спроби імпорту модуля не вдасться.
__init__.py
Файл зазвичай порожній, але може бути використаний для експорту окремих частин пакета під зручнішим назвою, трюмні зручні функції і т.д. З огляду на наведену вище приклад, вміст модуля ініціалізації можна звертатися як
import spam
виходячи з цього
__init__.py
був потрібний під Python 2.X і все ще потрібен під Python 2.7.12 (я тестував його), але він більше не потрібен від (нібито) Python 3.3 і далі, і не потрібен під Python 3.4.3 (I випробував це). Докладнішу інформацію див. У розділі stackoverflow.com/questions/37139786 .
__init__.py
.
setup.py
і ви використовуєте, find_packages()
це потрібно мати __init__.py
у кожному каталозі. Див stackoverflow.com/a/56277323/7127824
На додаток до мітки каталогу як пакету Python та визначення __all__
, __init__.py
дозволяє визначити будь-яку змінну на рівні пакету. Це часто зручно, якщо пакет визначає те, що буде імпортуватися часто, так, як API. Ця закономірність сприяє прихильності до піфонічної філософії "плоскіше, ніж вкладена".
Ось приклад одного з моїх проектів, в якому я часто імпортую sessionmaker
покликаний Session
взаємодіяти зі своєю базою даних. Я написав пакет "бази даних" з кількома модулями:
database/
__init__.py
schema.py
insertions.py
queries.py
Мій __init__.py
містить наступний код:
import os
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
engine = create_engine(os.environ['DATABASE_URL'])
Session = sessionmaker(bind=engine)
Оскільки я Session
тут визначаю , я можу розпочати новий сеанс, використовуючи синтаксис нижче. Цей код буде той самий, що виконується всередині або зовні каталогу каталогу "база даних".
from database import Session
session = Session()
Звичайно, це невелика зручність - альтернативою було б визначити Session
в новому файлі на зразок "create_session.py" в моєму пакеті баз даних і почати нові сеанси, використовуючи:
from database.create_session import Session
session = Session()
Тут є досить цікава нитка reddit, що висвітлює відповідне використання __init__.py
тут:
http://www.reddit.com/r/Python/comments/1bbbwk/whats_your_opinion_on_what_to_include_in_init_py/
Думається, що __init__.py
файли повинні бути дуже тонкими, щоб уникнути порушення філософії "явне краще, ніж неявне".
engine
, sessionmaker
, create_engine
, І os
все це може також бути імпортовано з database
... схоже , як ти наплутав це простір імен.
__all__ = [...]
обмеження того, що отримує з імпорту import *
. Але крім цього, так, вам залишається безладний простір імен верхнього рівня.
Існує 2 основні причини __init__.py
Для зручності: іншим користувачам не потрібно знати точне розташування ваших функцій у ієрархії ваших пакетів.
your_package/
__init__.py
file1.py
file2.py
...
fileN.py
# in __init__.py
from file1 import *
from file2 import *
...
from fileN import *
# in file1.py
def add():
pass
тоді інші можуть викликати додаток ()
from your_package import add
не знаючи file1, як
from your_package.file1 import add
Якщо ви хочете щось ініціалізувати; наприклад, ведення журналу (який слід поставити на верхньому рівні):
import logging.config
logging.config.dictConfig(Your_logging_config)
__init__.py
може бути корисним іноді, але не завжди.
Цей __init__.py
файл змушує Python розглядати каталоги, що містять його як модулі.
Крім того, це перший файл, який завантажується в модуль, тому ви можете використовувати його для виконання коду, який потрібно запустити щоразу, коли модуль завантажується, або вказати підмодулі, які потрібно експортувати.
Оскільки Python 3.3, __init__.py
більше не потрібно визначати каталоги як імпортні пакети Python.
Перевірити PEP 420: Неявні пакети простору імен :
Рідна підтримка каталогів пакетів, які не потребують
__init__.py
маркерних файлів і можуть автоматично охоплювати декілька сегментів шляху (надихнуті різними підходами сторонніх програм до пакетів простору імен, як описано в PEP 420 )
Ось тест:
$ mkdir -p /tmp/test_init
$ touch /tmp/test_init/module.py /tmp/test_init/__init__.py
$ tree -at /tmp/test_init
/tmp/test_init
├── module.py
└── __init__.py
$ python3
>>> import sys
>>> sys.path.insert(0, '/tmp')
>>> from test_init import module
>>> import test_init.module
$ rm -f /tmp/test_init/__init__.py
$ tree -at /tmp/test_init
/tmp/test_init
└── module.py
$ python3
>>> import sys
>>> sys.path.insert(0, '/tmp')
>>> from test_init import module
>>> import test_init.module
посилання:
https://docs.python.org/3/whatsnew/3.3.html#pep-420-implicit-namespace-packages
https://www.python.org/dev/peps/pep-0420/
Є __init__. py не потрібен для пакетів в Python 3?
У Python визначення пакету дуже просте. Як і Java, ієрархічна структура та структура каталогів однакові. Але ви повинні мати __init__.py
в пакеті. Я поясню __init__.py
файл на прикладі нижче:
package_x/
|-- __init__.py
|-- subPackage_a/
|------ __init__.py
|------ module_m1.py
|-- subPackage_b/
|------ __init__.py
|------ module_n1.py
|------ module_n2.py
|------ module_n3.py
__init__.py
може бути порожнім, доки він існує. Це вказує, що каталог слід розглядати як пакет. Звичайно,__init__.py
також можна встановити відповідний зміст.
Якщо ми додамо функцію в module_n1:
def function_X():
print "function_X in module_n1"
return
Після запуску:
>>>from package_x.subPackage_b.module_n1 import function_X
>>>function_X()
function_X in module_n1
Потім ми слідували за ієрархічним пакетом і називали module_n1 функцією. Ми можемо використовувати __init__.py
в subPackage_b так:
__all__ = ['module_n2', 'module_n3']
Після запуску:
>>>from package_x.subPackage_b import *
>>>module_n1.function_X()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named module_n1
Отже, використовуючи імпорт *, пакет модулів залежить від __init__.py
вмісту.
from package_x.subPackage_b.module_n1 import function_X
Хоча Python працює без __init__.py
файлу, ви все одно повинні включати його.
Він визначає, що пакет слід розглядати як модуль, тому включайте його (навіть якщо він порожній).
Також є випадок, коли ви можете фактично використовувати __init__.py
файл:
Уявіть, у вас була така файлова структура:
main_methods
|- methods.py
І methods.py
містив це:
def foo():
return 'foo'
Для використання foo()
вам знадобиться одне з наступних:
from main_methods.methods import foo # Call with foo()
from main_methods import methods # Call with methods.foo()
import main_methods.methods # Call with main_methods.methods.foo()
Можливо, там вам потрібно (або хочете) зберегти methods.py
всередині main_methods
(наприклад, час виконання / залежність), але вам потрібно лише імпортувати main_methods
.
Якщо ви змінили ім'я methods.py
на, __init__.py
ви можете використовувати foo()
його, просто імпортуючи main_methods
:
import main_methods
print(main_methods.foo()) # Prints 'foo'
Це працює, тому що __init__.py
розглядається як частина пакету.
Деякі пакети Python насправді роблять це. Приклад - JSON , де запущений import json
фактично імпорт __init__.py
із json
пакету ( див. Структуру файлу пакета тут ):
Вихідний код:
Lib/json/__init__.py
__init__.py
буде розглядати каталог, в якому він знаходиться, як модуль, що завантажується.
Для людей, які віддають перевагу читання коду, я розміщую тут коментар двобітного алхіміка .
$ find /tmp/mydir/
/tmp/mydir/
/tmp/mydir//spam
/tmp/mydir//spam/__init__.py
/tmp/mydir//spam/module.py
$ cd ~
$ python
>>> import sys
>>> sys.path.insert(0, '/tmp/mydir')
>>> from spam import module
>>> module.myfun(3)
9
>>> exit()
$
$ rm /tmp/mydir/spam/__init__.py*
$
$ python
>>> import sys
>>> sys.path.insert(0, '/tmp/mydir')
>>> from spam import module
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named spam
>>>
Це полегшує імпорт інших файлів python. Коли ви розмістили цей файл у каталозі (скажімо, речі), що містить інші файли py, ви можете зробити щось на зразок імпорту stuff.other.
root\
stuff\
other.py
morestuff\
another.py
Без цього __init__.py
всередині каталогу матеріалів ви не можете імпортувати other.py, оскільки Python не знає, де знаходиться вихідний код для цього матеріалу, і не може розпізнати його як пакет.
__init__.py
Файл робить імпорт легко. Якщо __init__.py
в пакет є присутність, функцію a()
можна імпортувати з файлу b.py
так:
from b import a
Однак без нього не можна імпортувати безпосередньо. Ви повинні внести зміни до системного шляху:
import sys
sys.path.insert(0, 'path/to/b.py')
from b import a