Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python one class per module and packages

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()
    
like image 278
Stefan Avatar asked Nov 09 '11 08:11

Stefan


People also ask

Should you have one class per file Python?

In Python there is rule of one module=one file. In Python if you restrict yourself to one class per file (which in Python is not prohibited) you may end up with large number of small files – not easy to keep track. So depending on the scenario and convenience one can have one or more classes per file in Python.

How many classes are in a Python module?

The rule is this: a module is the unit of reuse. Everything in Python libraries and other Python applications is either a module or a package of modules. There is no limit on how many classes one can put in a file or a module.

Are packages and modules same in Python?

A Python Module can be a simple python File (. py extension file), i.e., a combination of numerous Functions and Global variables. A Python Package is a collection of different Python modules with an __init__.py File. __init__.py Python File works as a Constructor for the Python Package.

Can we have more than one class with same name in different package in Python?

This is not possible with the pip. All of the packages on PyPI have unique names. Packages often require and depend on each other, and assume the name will not change. Even if you manage to put the code on Python path, when importing a module, python searches the paths in sys.


3 Answers

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.)
like image 108
gurney alex Avatar answered Oct 14 '22 07:10

gurney alex


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().

like image 23
jro Avatar answered Oct 14 '22 09:10

jro


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.
like image 25
Joël Avatar answered Oct 14 '22 07:10

Joël