Python - почему я могу импортировать модули без __init__.py?

Я новичок в Python, и я все еще не могу понять, зачем нам нужен файл __init__.py для импорта модулей. Я рассмотрел другие вопросы и ответы, например .

Что меня смущает, я могу импортировать свои модули без __init__py, поэтому зачем мне это вообще нужно?

Мой пример,

index.py
   modules/
      hello/
          hello.py
          HelloWorld.py

index.py,

import os
import sys

root = os.path.dirname(__file__)
sys.path.append(root + "/modules/hello")

# IMPORTS MODULES
from hello import hello
from HelloWorld import HelloWorld

def application(environ, start_response):

    results = []

    results.append(hello())

    helloWorld = HelloWorld()
    results.append(helloWorld.sayHello())

    output = "<br/>".join(results)

    response_body = output

    status = '200 OK'

    response_headers = [('Content-Type', 'text/html'),
                       ('Content-Length', str(len(response_body)))]

    start_response(status, response_headers)

    return [response_body]

модули/Привет/hello.py,

def hello():
    return 'Hello World from hello.py!'

модули/Привет/HelloWorld.py,

# define a class
class HelloWorld:
    def __init__(self):
        self.message = 'Hello World from HelloWorld.py!'

    def sayHello(self):
        return self.message

Результат

Hello World from hello.py!
Hello World from HelloWorld.py!

Что нужно, это просто эти две строки,

root = os.path.dirname(__file__)
sys.path.append(root + "/modules/hello")

Без __init__py. Может кто-нибудь объяснить, почему он работает таким образом?

Если __init__py является правильным способом, что мне делать/изменять в моем коде?

Ответ 1

Я думаю, что это хороший 'answer' для того, что я не понял.

myMath/
    __init__.py
    adv/
        __init__.py
        sqrt.py
        fib.py
    add.py
    subtract.py
    multiply.py
    divide.py

MyMath/__ __ INIT. Ру

from add import add
from divide import division
from multiply import multiply
from subtract import subtract
from adv.fib import fibonacci
from adv.sqrt import squareroot

index.py

import sys

sys.path.append('C:\Users\mdriscoll\Documents')

import mymath

print mymath.add(4,5)
print mymath.division(4, 2)
print mymath.multiply(10, 5)
print mymath.fibonacci(8)
print mymath.squareroot(48)

Ответ 2

__init__.py для пакетов. Пакет содержит набор связанных модулей. Если у вас только один модуль, который вы хотите использовать, вам не нужно использовать __init__.py; просто поместите одиночный файл .py где-нибудь на системный путь, и вы можете его импортировать.

Цель пакетов - не только позволить вам импортировать модули внутри них. Он объединяет модули вместе. Главное преимущество этого заключается в том, что если модуль находится внутри пакета, то этот модуль может импортировать другие модули из пакета с использованием относительного импорта. Если у вас есть foo.py и bar.py в одном пакете, тогда foo может просто сделать from . import bar. Это делает импорт внутри пакета более компактным и проще реорганизовать, если вы реструктурируете пакет или измените его имя.

Кроме того, очевидное преимущество., если вы делаете это пакетом, вам не нужно делать это sys.path каждый раз, когда вы хотите что-то импортировать из него.

Ответ 3

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

[email protected] ~/temp $ tree .
.
├── main.py
└── packages
    ├── file.py
    └── file.pyc

1 directory, 5 files

содержимое main.py:

import packages.file as p
p.fun()

и содержимое файла file.py:

import sys
def fun():
  print(sys.path)

Когда я выполняю main.py с Python 2.7.12, я получаю ImportError, а выполнение main.py с Python 3.5.2 просто работает.

После добавления __init__.py в каталог пакетов код работает с обеими версиями Python.

Ответ 4

Файлы с именем __init__.py используются для маркировки каталогов на диске в виде каталогов пакетов Python. Если у вас есть файлы

modules/hello/__init__.py
modules/hello/module.py

и modules находится на вашем пути, вы можете импортировать код в module.py как

import spam.module

или

from spam import module

Если вы удалите файл __init__.py, Python больше не будет искать подмодули внутри этого каталога, поэтому попытки импортировать модуль не удастся.

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

import spam

И, наконец, вот что официальная документация должна сказать об этом файле:

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

Ответ 5

На основе этой ссылки: с Python 3.3

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