6

I'm trying to structure my app in Python. Coming back from C#/Java background, I like the approach of one class per file. I'd like my project tree to look like this:

[Service]
    [Database]
        DbClass1.py
        DbClass2.py
    [Model]
        DbModel1.py
        DbModel2.py
    TheService.py
[ServiceTests]
    [Database]
        DbClass1Tests.py
        DbClass2Tests.py
    [Model]
        DbModel1Tests.py
        DbModel2Tests.py
    TheServiceTests.py
  1. Is the one class per file approach OK in Python?
  2. Is it possible to create packages/modules in such a way so that packages work like Java's packages or .NET's namespaces, i.e. in DbModel1Tests.py:

    import Service.Model
    
    def test():
       m = DbModel1()
    
Cédric Julien
  • 78,516
  • 15
  • 127
  • 132
Stefan
  • 4,166
  • 3
  • 33
  • 47

4 Answers4

13

Q1. You can use the 1 class per file style in Python, but this is unusual.

Q2. you'd have to use from Service.Model import * and do some stuff in Service/Model/__init__.py which is generally frowned upon. Avoid import * in Python

My personal advice on this: Python is not C#/Java. Trying to bend it to make it look like $other_language will cause frustration and poor user experience.

Keep in mind that:

  • you can have other stuff than classes in Python modules (functions, for instance)
  • you don't have to import a class from a module unless you need to instantiate that class. Especially, if your code only uses instances of DbModel1 which are passed as arguments to your functions / methods, there is no need for the import in that part of the code
  • from Service.Model.DbModel1 import DbModel1 looks bad. Prefer from service.model import DbModel1 : avoid uppercase letters in file names and directory names, and group classes / functions logically in files (rather than grouping them in directories as you would do with the 1 class per file system.)
the
  • 21,007
  • 11
  • 68
  • 101
gurney alex
  • 13,247
  • 4
  • 43
  • 57
  • 1
    Why is having one class for file unusual in Python? – Gewthen Sep 28 '15 at 12:55
  • @Gewthen it is not mandated by the language, so it is not a common practise. – gurney alex Oct 09 '15 at 10:59
  • 2
    Regardless of whether I agree or disagree, this answer could be made more useful if some of the "do's and don't" have some explanation and reasoning behind them. Mentioning pep 8 would help on some of your points, but others need more (e.g. "generally frowned upon", "looks bad"). – Gewthen Oct 16 '15 at 21:29
4

In my opinion, for 1: I don't see why not. I think, regardless of language this is a good idea as it provides you with a quick overview of what is to be found in a file when you know there will be only a single class in it. I would make a small exception for helper classes though, but as Python allows nested classes this can also be done quite nicely.

For 2: possible as well. In your example though, you simple load the module, thereby making its classes and functions available by the full namespace.

So, if you say import Service.Model, you can only access the class by using m = Service.Model.DBModel1().

To import things into the current namespace, do a from Service.Model import * (or from Service.Model import DBModel1 if you only need that class). Then you can do as you currently do: m = DBModel1().

jro
  • 9,300
  • 2
  • 32
  • 37
  • 5
    The end seems a little misleading - using the OP's structure, wouldn't one need to write `m = DBModel1.DBModel1()` after `from Service.Model import DBModel1` (assuming class name is same as that of the .py file) ? – jwd Nov 20 '13 at 23:30
3

You can have one class per module, but this is not required. I would say that it's more related to the length of each module (keeping them not too long is always a good idea).

Now, about your structure:

  • you can declare your sub-folders as packages. For this, just create an __init__.py file in each sub-folder.
  • once this is done, you can import the modules like this: from Service.Model import DbModel and use this as you wrote: m = DbModel1.DbModel1Class()

Notes:

  • naming your files with first letter as uppercase is not really Pythonic (but class name should have it). This means that it should look like service.model.dbModel1.DbModel1().
  • you can do from Service.Model import DbModel1 to directly import class from DbModel1 module. This can be done through correct setting of __init__.py content (I don't know how to configure it exactly). Some more informations here.
Community
  • 1
  • 1
Joël
  • 2,723
  • 18
  • 36
0

A python system is a set of modules, each module has a target, so you need use the most suitable approach to reach the target, it includes a class per module or a mix of functions and classes per module.

Canatto Filipe
  • 569
  • 7
  • 15