0

I currently have a folder structure like this:

.
├── main.py
└── parent.py
└── classes
    └── subclass1.py
    └── subclass2.py
    └── subclass3.py

Each of the subclasses are a subclass of parent, and parent is an abstract class. The subclasses need to execute some functions like mix() and meld(), and each of these subclasses must implement mix() and meld().

I would like to write main.py such that the functions in each of the subclasses are executed, without me having to import their files into my program. That is, I'd like something akin to the following to happen:

def main():
    # Note that I don't care about the order of which these
    for each subclass in the sources folder:
        execute `mix()` and `meld()`
        # Note that I don't mind which order the order 
        # of which the subclasses' functions are invoked.

Is there any way I could get this to happen?

Essentially, what I want to do is drop a bunch of classes into the classes folder, with only mix() and meld() defined, and let this program run wild.

hlin117
  • 20,764
  • 31
  • 72
  • 93

2 Answers2

1

I've never tried this, but I think it does what you're asking for:

import os
import imp
import runpy

package = 'classes'

_, path, _ = imp.find_module(package)
for m in os.listdir(path):
    if m.endswith('.py'):
        runpy.run_module(
            package + '.' + os.path.splitext(m)[0], 
            run_name="Mix_Meld"
        )

Then, inside of your subclasses, you can write:

if __name__ == 'Mix_Meld':
    ClassName.mix()
    ClassName.meld()

This may result in additional code, granted, but if you ever need to stop the execution in one of the files, doing so is just a matter of commenting out that part of the code.

Another advantage is extensibility and polymorphism; if you need to run the code a bit differently for each one of these modules in the future, you only have to change the behaviour in the specific modules. The callee (main.py) will remain oblivious to those changes and continue calling the modules the usual way.

Eithos
  • 2,421
  • 13
  • 13
  • Wow, today I learned `runpy` was a thing. Thank you very much. – hlin117 Feb 08 '15 at 03:07
  • @hlin117 No problem. I also fixed a small mistake-- I was missing the dot operator (`.`) between the package name (`classes`) and the modules names. – Eithos Feb 08 '15 at 06:53
  • I actually hit an error on the line `imp.find_module(package)`. I had to use this stackoverflow suggestion: http://stackoverflow.com/a/4383597/2014591 – hlin117 Feb 11 '15 at 17:27
  • @hlin117 That's normal. It really depends on how you've set up your environment variables and/or how you've organized your project structure. As you can see in the docs for [imp](https://docs.python.org/2/library/imp.html), when you don't supply a path argument, `find_module` uses _"the list of directory names given by sys.path"_. I don't usually modify sys.paths, personally, but it is a valid approach in certain cases. – Eithos Feb 11 '15 at 17:37
  • @hlin117 Just as a quick addition to that, you could have also (as I just alluded to) used `find_module` _as is_ by supplying that optional `path` argument. It's a bit cleaner IMO, but really it boils down to preference. – Eithos Feb 11 '15 at 17:42
0

Try importing from the subfolder in the main.py program file:

from glob import *
import os

for i in glob.glob(os.path.join('classes', '*.py')):
    __import__(i); className = i[:-3].capitalize()
    eval(className).mix(); eval(className).meld()
Malik Brahimi
  • 16,341
  • 7
  • 39
  • 70