It is a good practice to import modules in __init__.py

5

I noticed that in the Django framework modules are imported into __ init __ .py for convenience.

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

So this:

from django.forms.forms import Form

It becomes this:

from django.forms import Form

This leaves the code more readable, but updating the __ init __ .py file in a constantly evolving application seems tedious. Is it a good practice to do this on something other than a framework? Are there tools that facilitate this process?

    
asked by anonymous 05.06.2014 / 15:46

1 answer

7

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

Framework components can grow to become very complicated. Imagine how Django forms code should be great! We already know, however, how to deal with large codes: we split 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 call MarkdownPage etc. If we used a single file, we would have a structure like this:

- 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 user of the framework 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 in __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

How well well said Phillip J. Eby :

  

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

So, to help the lives of our users, we import all classes in __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 small, and all the code fit elegantly in page.py . Gradually, it grew, and we resolved to separate it into different files. In this case importing everything in __init__.py is even more important, since it allows codes that used the old version to continue running on the new one.

To leave the namespace clean

Suppose our MarkdownPage class uses a MarkdownParser class. In the case where times only a large page.py , MarkdownParser will be available to those who import page.py . However, this is not ideal: MarkdownParser is an implementation detail.

By putting MarkdownPage to markdown.py , we can import only what we want from it into __init__.py , clearing the namespace .

Is it worth out of frameworks?

Well, that depends ... On small projects, almost certainly not. But look, if your project is large and has a good architecture, it will be modular, so some components of it will be, for general purposes, frameworks that other parts of the same project will use, right? So, do not be surprised if this pattern appears on other projects as well.

    
05.06.2014 / 16:26