41

I'm new to Python and I still can't get my head around why we need a __init__.py file to import modules. I have gone through other questions and answers, such as this.

What confuses me is that I can import my modules without __init__py, so why do I need it at all?

My example,

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]

modules/hello/hello.py,

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

modules/hello/HelloWorld.py,

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

    def sayHello(self):
        return self.message

Result,

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

What it takes is just these two lines,

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

Without any of __init__py. Can someone explain why it works in this way?

If __init__py is the proper way, what should I do/change in my code?

Community
  • 1
  • 1
Run
  • 54,938
  • 169
  • 450
  • 748

5 Answers5

28

Based on this link: Since Python 3.3

Allowing implicit namespace packages means that the requirement to provide an __init__.py file can be dropped completely

Brian Burns
  • 20,575
  • 8
  • 83
  • 77
Nurgling96
  • 566
  • 5
  • 18
  • 2
    this should be the accepted answer, because it answers the question. – dashesy Apr 28 '20 at 17:27
  • It doesn't answer the part "why do I need it at all", though. *All* answers should answer the question by definition. Which of them is "accepted" is up to the asker. – mkrieger1 Feb 08 '23 at 12:06
20

__init__.py is for packages. A package contains a collection of related modules. If you just have a single module you want to use, you don't need to use __init__.py; just put the single .py file somewhere on the system path and you can import it.

The purpose of packages is not just to allow you to import the modules inside them. It's to group the modules together. The main benefit of this is that, if a module is inside a package, then that module can import other modules from the package using relative imports. If you have foo.py and bar.py in the same package, then foo can just do from . import bar. This makes intra-package imports more compact and easier to reorganize if you restructure the package or change its name.

Also, an obvious benefit is. . . if you make it a package, you don't have to do that sys.path stuff every time you want to import something from it.

BrenBarn
  • 242,874
  • 37
  • 412
  • 384
  • 1
    Another big advantage of packages is separating namespaces. If you write your own `json` module, it will shadow the global `json` module. But if you make it `mypackage.json`, it won't cause such conflicts (at least in Python 3 or Python 2 with `from __future__ import absolute_import`). – Blckknght Aug 22 '15 at 04:48
  • Thanks. Can you show me an example of package that requires `__init__.py`? thanks. – Run Aug 22 '15 at 04:48
  • 5
    @teelou: In Python versions prior to 3.3, all packages were *required* to have an `__init__.py` file. Python 3.3 removed this requirement, see [PEP 420](https://www.python.org/dev/peps/pep-0420/). It sounds like you might not know much about packages though, so before reading the PEP, you might want to read [the appropriate section of the Python docs](https://docs.python.org/2/tutorial/modules.html#packages) first. – Blckknght Aug 22 '15 at 04:55
10

I think that this might be due to Python version you are using. I did some experimentation and found out that having following structure:

jedrzej@jedrzej-UX303LB ~/temp $ tree .
.
├── main.py
└── packages
    ├── file.py
    └── file.pyc

1 directory, 5 files

content of main.py:

import packages.file as p
p.fun()

and content of file.py:

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

When I am executing main.py with Python 2.7.12 I get ImportError while execution of main.py with Python 3.5.2 simply works.

After adding __init__.py in packages directory, code works with both versions of Python.

jedruniu
  • 520
  • 4
  • 13
4

Files named __init__.py are used to mark directories on disk as Python package directories. If you have the files

modules/spam/__init__.py
modules/spam/module.py

and modules is in your path, you can import the code in module.py as

import spam.module

or

from spam import module

If you remove the __init__.py file, Python will no longer look for submodules inside that directory, so attempts to import the module will fail.

The __init__.py file is usually empty, but can be used to export selected portions of the package under a more convenient name, hold convenience functions, etc. Given the example above, the contents of the init module can be accessed with

import spam

And finally here is what the official documentation has to say about this file:

The __init__.py files are required to make Python treat the directories as containing packages; this is done to prevent directories with a common name, such as string, from unintentionally hiding valid modules that occur later on the module search path. In the simplest case, __init__.py can just be an empty file, but it can also execute initialization code for the package or set the __all__ variable, described later.

zell
  • 9,830
  • 10
  • 62
  • 115
Shawn Mehan
  • 4,513
  • 9
  • 31
  • 51
  • `mydir/spam/__init__.py mydir/spam/module.py` isn't the same as `modules/hello/hello.py` in my example? – Run Aug 22 '15 at 04:51
  • no, @teelou, they weren't the same string. But they were similar. it is meant as an abstract example to assist in the generalization of the concept. But I have edited the file to make the abstraction go away and ease the burden. good luck. – Shawn Mehan Aug 22 '15 at 05:01
  • where do you use `import spam.module`? And where is the entry point - such as index.py? – Run Aug 22 '15 at 05:06
  • You could use `import spam module` in any other python file, so long as `modules` is on your path. I'm sorry, I'm not certain what you mean by *entry point*. Read @BrenBarn answer also in this thread. It's insightful. – Shawn Mehan Aug 22 '15 at 05:10
3

I think this is a good 'answer' for what I didn't understand.

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

myMath/__init__.py

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)
Shawn Mehan
  • 4,513
  • 9
  • 31
  • 51
Run
  • 54,938
  • 169
  • 450
  • 748