12

I am developing a rather complex application for my company following the object-oriented model in python3. The application contains several packages and sub-packages, each - of course - containing an __init__.py module.

I mostly used those __init__.py modules to declare generic classes for the package inside them, which are intended to be used as abstract templates for their respective package only.

My question is now: Is this a "nice" / "correct" / "pythonic" way to use the __init__.py module(s)? Or shall I rather declare my generic classes somewhere else?

To give an example, let's assume a package mypkg:

mypkg.__init__.py:

class Foo(object):
    __some_attr = None

    def __init__(self, some_attr):
        self.__some_attr = some_attr

    @property
    def some_attr(self):
        return self.__some_attr

    @some_attr.setter
    def some_attr(self, val):
        self.__some_attr = val

mypkg.myfoo.py:

from . import Foo

class MyFoo(Foo):
    def __init__(self):
        super().__init__("this is my implemented value")

    def printme(self):
        print(self.some_attr)
Richard Neumann
  • 2,986
  • 2
  • 25
  • 50
  • 9
    Is your current approach causing any headaches? Changing something which is working fine because somebody might consider it unpythonic is unpythonic. – timgeb Jun 17 '14 at 14:33
  • I always thought of `__init__.py`, if used for anything at all, to be for module initialization (such as creating any module-wide state objects, etc) and for presenting the public interface of the module. Another way to think about it, I think, is that `__init__.py` performs the analogous role for the module object created when the module is imported as the `__init__()` method of a class performs for a newly created instance of that class. – Silas Ray Jun 17 '14 at 14:33
  • @timgeb There is no technical or conceptional problem whatsoever. The application works just fine. Nonetheless I am new to python and now want to tidy up stuff, to make it follow the PEPs. @SilasRay So what's your proposal then? Shall I put the abstract classes in some module `abstract.py ` or `templates.py`? – Richard Neumann Jun 17 '14 at 14:57
  • My personal opinion: it would be the last place I would look for something like that, so assuming I'm not alone, you're probably going to confuse other people who read your code. I don't think that's Pythonic. – Mark Jun 17 '14 at 16:38

4 Answers4

4

It depends by what is the API you want to provide. For example the collections module in the standard library defines all the classes in the __init__.py1. And the standard library should be pretty "pythonic", whatever that means.

However it provides mostly a "module-like" interface. It's quite rare to see:

import collections.abc

If you already have subpackages you are probably better introducing a new subpackage. If, currently, the use of the package doesn't actually depend on subpackages you might consider putting the code in the __init__.py. Or put the code in some private module and simply import the names inside __init__.py (this is what I'd prefer)


If you are only concerned with where it's better to put the Abstract Base Classes, as shown above (collections.abc contains the abstract base classes of the collections package), and as you can see from the standard library's abc module, it's common to define an abc.py submodule that contains them. You may consider exposing them directly from the __init__.py doing:

from .abc import *
from . import abc

# ...
__all__ = list_of_names_to_export + abc.__all__

inside your __init__.py.


1 The actual implementation used is in C however: _collectionsmodule.c

Bakuriu
  • 98,325
  • 22
  • 197
  • 231
4

You can always put everything into one source file. The reason for splitting the more complex code into separate modules or packages is to separate the things that are mutually related from things that are unrelated. The separated things should be as independent as possible on the rest. And it applies to any level: data structures, functions, classes, modules, packages, applications.

Inside the module or inside the package should apply the same rules. I agree with Bakuriu that __init__.py should be closely related to the package infrastructure, but not neccessarily to the functionality of the module. My personal opinion is that the __init__.py should be as simple as possible. The reason firstly is that everything should be as simple as possible but not simpler. Secondly, people reading the code of your package tend to think that way. They may not expect the unexpected functionality in __init__.py. It would probably be better to create generic.py inside the package for the purpose. It is easier to document the purpose of the module (say via its top docstring).

The better the separation is from the beginning, the better can the independent features be combined in future. You get better flexibility -- both for the usage of module inside the package and also for future modifications.

Community
  • 1
  • 1
pepr
  • 20,112
  • 15
  • 76
  • 139
0

It is indeed possible to use __init__.py for a specific module initialization, but I have never seen someone using it to define new functions. The only "correct" use I know is what is discussed in this subject ....

Anyway, as you might have a complex application, you can use a temporary file where you define all your needed functions instead of defining them directly in __init__.py module. This will allow you more readability it is easier to change afterwards.

Community
  • 1
  • 1
Taha
  • 709
  • 5
  • 10
  • What do you mean by _temporary_ _file_? I am not defining raw functions in `__init__.py`. I am defining generic _classes_ there to be extended by other classes in the respective packages' sub-packages and modules. – Richard Neumann Jun 17 '14 at 15:07
0

Don't ever use __init__.py for anything except to define __all__. You will save so many lives if you will avoid it.

Reason: It is common for developers to look at packages and modules. But there is a problem you can stuck with sometimes. If you have package, you assume that there is a modules and code inside of it. But you will rarely count __init__.py as one, because, let's face it, most times it is just a requirement to make modules from directory importable.

package
    __init__.py
    mod1.py
    humans.py
    cats.py
    dogs.py
    cars.py
    commons.py

Where should be located class Family? It is common class and it depends on others, because we can create family of humans, dogs and cats, even cars!

By my logic, and logic of my friends, it should be places in separated file, but I will try to find it in commons, next in humans and then... I will be embarrassed, because I don't really know where it is!

Stupid example, huh? But it gives a point.

dt0xff
  • 1,553
  • 1
  • 10
  • 18
  • There are **many** more *completely* legit usages. Two simple examples: loading modules that are OS specific. Providing commonly used objects that are definined in submodules. – Bakuriu Jun 17 '14 at 17:03
  • Yea, this is what I mean "defining `__all__`" - just loading and providing modules. – dt0xff Jun 17 '14 at 17:05