2

My problem might be more linked to OOP than python. I wrote a class in order to describe a molecule and then I wrote a function in order to create a molecule object from a specific file format : fromFILE. Thus, for example, I do the following when I use my class :

import mymodule
mol = mymodule.fromFILE("toto")
mol.method()
...

My question is what is the good way for organizing things. Should the function fromFILE() be a part of the class or not and if yes what is the best way to write this ?

Until now, I just put the class and the functions which can be used to create this class into the same module but I do not know if this is the best way to do that.

Ger
  • 9,076
  • 10
  • 37
  • 48

2 Answers2

8

You can make it a class method:

class Molecule(object):
    # ...

    @classmethod
    def fromFile(cls, filename):
        data = # ... parse data from filename ...
        return cls(data)

This has the added advantage that subclasses can simply inherit it, or override it to adjust what the method does (including calling the original parent implementation). It provides an alternative class factory:

import mymodule

mol = mymodule.Molecule.fromFile('toto')

neatly grouping this factory with the class itself.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • and OP could even do `fromFile = Molecule.fromFile` to have the function available at the class and module level. – mgilson Jun 25 '13 at 12:58
  • this strikes me as breaking SOLID, most importantly the Single responsibility. The molecule should really only care about molecule things not about loading. – Mgetz Jun 25 '13 at 13:06
  • I don't even think there's a problem with OO here, constructors should go on the object, yes? – Brian Hicks Jun 25 '13 at 13:06
  • @Mgetz: The Python `datetime` library does this; it keeps the constructors grouped with the object type they construct. `datetime.fromtimestamp()`, `date.today()`, etc. are all class methods that construct their respective types. – Martijn Pieters Jun 25 '13 at 13:11
  • @MartijnPieters constructors yes, as those should contain business logic. However in this case I don't believe that File IO is germane to that business logic. I could see having a constructor on Molecule that was something like `Molecule.react()` or `Molecule.decompose()` which in turn create new `Molecule` – Mgetz Jun 25 '13 at 13:15
  • Here a short example explaining `@classmethod` directive particularly in the case of new constructors : http://stackoverflow.com/a/12179752/1421907 – Ger Jun 25 '13 at 13:15
  • @Mgetz I understand what you mean. But practically 99% of the aim of this class is : 1) load molecule from a file, 2) do a transformation (geometrical transformation), 3) export molecule into a new class. Thus even if this kind of constructor is not in the OOP spirit they are really useful. – Ger Jun 25 '13 at 13:20
  • @Ger that is why the repository pattern is useful, because it allows you to abstract out persistence, who knows you may move your persistence in the future from a text file to a database or NoSQL. If you put the persistence information in the class then you are required to code a new constructor each and every time. If you use a repository that is not the case, the business logic remains in the Molecule and the persistence in the repository. – Mgetz Jun 25 '13 at 13:23
0
  1. Does the behavior of your molecule care about file IO? Probably not, this suggests that the molecule is an entity and should be persistence ignorant. At the same time it needs to enforce its own business logic.
  2. Is the information needed to construct a molecule itself business logic? if so then you may want to consider using either the repository pattern or the factory pattern, or a combination of the two (what I would do)

ex:

import repositories
mol = repositories.MoleculeRepository.FromFile('toto')
Mgetz
  • 5,108
  • 2
  • 33
  • 51