It is good practice to import modules into __init__.py

Asked

Viewed 1,073 times

5

I noticed that in Django framework modules are imported into __init__.py for convenience.

"""
Django validation and HTML form handling.
"""
from django.forms.forms import *  # NOQA

That way it:

from django.forms.forms import Form

Becomes that:

from django.forms import Form

This makes the code more readable, but update the file __init__.py in a constantly developing application seems tedious. Is it a good practice to do this in something other than a framework? There are tools that facilitate this process?

1 answer

7


You kind of killed the riddle. My impression is also that this is natural in frameworks.

Frameworks components can grow to become quite complicated. Imagine how big Django’s form code must be! We already know, however, how to handle large codes: we divide them into several files.

Why create multiple files

Consider a hypothetical framework, for example, that has several types of classes that represent Web pages. All will inherit from a base class called Page; there will be a class that only serves static content of a file, and will be called ResourcePage; another class will have several facilities for Javascript and CSS, and will be called RichPage; a third one can read Markdown and generate HTML and will be called MarkdownPage etc. If we used only one file, we would have a structure like below:

- framework
   - page.py

And page.py would have several classes:

class Page(object):
    # ...
    pass

class ResourcePage(Page):
    # ...
    pass

class RichPage(Page):
    # ...
    pass

class MarkdownPage(Page):
    # ...
    pass

# E assim por diante...

The framework user can write something simple with from framework.page import RichPage, but certainly page.py will be huge! An alternative is to create multiple files:

- framework/
  - page/
    - page.py
    - resource.py
    - rich.py
    - markdown.py
    - __init__.py

The code will be much more maintainable, right?

Because you want to import classes into __init__.py

To facilitate

The code will be more maintainable, but now our poor user should import classes like this:

from framework.page.rich import RichPage

Like well said Phillip J. Eby:

a Python programmer [...] will probably get annoyed when typing Foo.Foo.someMethod when it should just be Foo.someFunction.

So, to help our users' lives, we import all classes into __init__.py:

from .page import Page
from .resource import ResourPage
from .rich import RichPage
from .markdown import MarkdownPage

Now our user can happily just invoke:

from framework.page import MarkdownPage

Not to break what already worked

Sometimes the main reason for this is backward compatibility. Our framework was tiny, and all the code fit elegantly in the page.py. Gradually, it grew, and we decided to separate it into different files. In this case import everything in __init__.py is even more important as it allows codes that used the old version to continue running in the new.

To keep the namespace clean

Suppose our class MarkdownPage use a class MarkdownParser. In the event that times only a great page.py, MarkdownParser will be available to anyone who imports page.py. However, this is not ideal: MarkdownParser is a detail of implementation.

By placing the MarkdownPage in markdown.py, we can only import what we want from her into the __init__.py, cleaning the namespace.

Worth out of frameworks?

Well, that depends... on small projects, almost certainly not. But look, if your project is big and has a good architecture, it will be modular, then some of its components will be, for general purposes, frameworks what other parts of the same project will use, right? So, don’t be surprised if this pattern appears in other projects as well.

  • Excellent explanation. Thank you.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.