60

I like the Java convention of having one public class per file, even if there are sometimes good reasons to put more than one public class into a single file. In my case I have alternative implementations of the same interface. But if I would place them into separate files, I'd have redundant names in the import statements (or misleading module names):

import someConverter.SomeConverter

whereas someConverter would be the file (and module) name and SomeConverter the class name. This looks pretty inelegant to me. To put all alternative classes into one file would lead to a more meaningful import statement:

import converters.SomeConverter

But I fear that the files become pretty large, if I put all related classes into a single module file. What is the Python best practise here? Is one class per file unusual?

deamon
  • 89,107
  • 111
  • 320
  • 448
  • 8
    By the time you're dealing with a project consisting of 10'000 classes, you'll be happy if you can find a (public) class by its file (and package) name instead of having to search the contents of all files.. that's probably the rationale why Java enforces that there is only one public class per file and that the file name must be the class name. – Andre Holzner Oct 01 '10 at 20:10

3 Answers3

60

A lot of it is personal preference. Using python modules, you do have the option to keep each class in a separate file and still allow for import converters.SomeConverter (or from converters import SomeConverter)

Your file structure could look something like this:

* converters
     - __init__.py
     - baseconverter.py
     - someconverter.py
     - otherconverter.py

and then in your __init__.py file:

from baseconverter import BaseConverter
from otherconverter import OtherConverter
Zach
  • 18,594
  • 18
  • 59
  • 68
49

Zach's solution breaks on Python 3. Here is a fixed solution.

A lot of it is personal preference. Using python modules, you do have the option to keep each class in a separate file and still allow for import converters.SomeConverter (or from converters import SomeConverter)

Your file structure could look something like this:

* converters
     - __init__.py
     - baseconverter.py
     - someconverter.py
     - otherconverter.py

and then in your __init__.py file:

from converters.baseconverter import BaseConverter
from converters.otherconverter import OtherConverter
Spundun
  • 3,936
  • 2
  • 23
  • 36
  • 7
    How about just "from .baseconverter import BaseConverter" ? – Michael Clerx Feb 01 '14 at 15:09
  • Sorry for the late follow up, I've been out of touch with python in recent times, if someone can verify Michael's solution above then please feel free to edit my answer and add that as alternative. (Don't change my original because I think it's a matter of preference as to which one looks more readable so let's give the users both the options) – Spundun Mar 10 '14 at 16:29
  • 8
    Michael's answer does work, but PEP 8 discourages relative imports. http://stackoverflow.com/questions/4209641/absolute-vs-explicit-relative-import-of-python-module – Jason Pearson Apr 26 '14 at 13:34
  • 3
    @JasonPearson Not anymore, explicit relative imports are fine for intra-package imports: https://mail.python.org/pipermail/python-dev/2010-October/104476.html – Géry Ogam Dec 05 '18 at 15:46
3

The above solutions are good, but the problem with importing modules in __init__.py is that this will cause all the modules to be loaded twice(inefficient). Try adding a print statement at the end of otherconverter.py and run otherconverter.py. (You'll see that the print statement is executed twice)

I prefer the following. Use another package with name "_converter" and define everything there. And then your "converters.py" becomes the interface for accessing all public members

* _converters
     - __init__.py
     - baseconverter.py
     - someconverter.py
     - otherconverter.py

*  converters.py

where converters.py is

from _converters.someconverter import SomeConverter
from _converters.otherconverter import OtherConverter
...
...
...
converters = [SomeConverter, OtherConverter, ...]

And as the previous solutions mentioned, it is a personal choice. A few practices involve defining a module "interace.py" within the package and importing all public members here. If you have many modules to load, you should choose efficiency over aesthetics.