5

Let's consider an application where I have a base class Move and its variants Walk and Run. I would like to split them into separate classes. I would also like to be able to get a list of possible movements from the base class. Something like:

Module 1:

class Move(object): pass

Module 2:

from module1 import Move
class Walk(Move): pass

Main script:

from module1 import *
from module2 import *
print Move.__subclasses__()

Without these two import lines the main will return no subclasses. This seems to be an expected behaviour.

I would like to be able to add more movement modules in future, without modifying the existing source code.

I am thinking of discovering and importing all python files in a given directory, similar to what is done here: Python __subclasses__() not listing subclasses

Is there a cleaner way for such task?

Community
  • 1
  • 1
Eka AW
  • 231
  • 1
  • 9
  • 1
    Bit of a rhetorical question: Let's say I come along, see your Move class, fork your code and subclass Move (and let's call that subclass Swim). Does it make any sense for your `Move.__subclasses__()` to know about Swim? – NightShadeQueen Sep 01 '15 at 15:56
  • It is not in requirements we have today to have multiple levels of inheritance for movements. The developer guide of the software will state that all movement classes have to be inherited from Move.
    In future, if we see any need for additional layers (Move -> Swim -> (Butterfly, Breaststroke), we were planning to set up a recursive subclasses search similar to http://stackoverflow.com/questions/3862310/how-can-i-find-all-subclasses-of-a-given-class-in-python
    However now that I am rethinking of all this, looping through all modules will just to the same.
    – Eka AW Sep 01 '15 at 16:22
  • In fact, I am not sure I have got your example quite well. Yes, any particular movement makes sense for Move. – Eka AW Sep 01 '15 at 16:26

1 Answers1

3

Without importing subclasses python has no way of knowing about them.

Solution we used in one project which in the end accomplished exactly what you are asking for was to use entry_points. And then loading classes defined via entry points.

Entry point definition:

module.movements = 
    Swim = othe_module:Swim
    Run  = other_module:Run

Loading entry points:

def load_registred_entry_points(group):
    for ep in pkg_resources.iter_entry_points(group=group):
        ep.load()

load_registred_entry_points('module.movements')

Of course you have to call load_registred_entry_points before calling Move.__subclasses__().

beezz
  • 2,398
  • 19
  • 15