Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it pythonic to use __init__.py modules of a package for generic, abstract classes?

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)
like image 722
Richard Neumann Avatar asked Jun 17 '14 14:06

Richard Neumann


People also ask

Is __ init __ py necessary?

If you have setup.py in your project and you use find_packages() within it, it is necessary to have an __init__.py file in every directory for packages to be automatically found.

What is the use of file __ init __ py in a package?

The __init__.py file makes Python treat directories containing it as modules. Furthermore, this is the first file to be loaded in a module, so you can use it to execute code that you want to run each time a module is loaded, or specify the submodules to be exported.

What is the use of file __ init __ py in a package even when it is empty?

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. Leaving an __init__.py file empty is considered normal and even a good practice, if the package's modules and sub-packages do not need to share any code.

Which of the following module helps in creating abstract classes in Python?

The 'abc' module in Python library provides the infrastructure for defining custom abstract base classes. 'abc' works by marking methods of the base class as abstract.


Video Answer


2 Answers

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.

like image 72
pepr Avatar answered Nov 15 '22 15:11

pepr


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

like image 25
Bakuriu Avatar answered Nov 15 '22 15:11

Bakuriu