2009-01-23 8 views
3

J'ai un tas de modules Python dans un répertoire, tous étant une classe dérivée. J'ai besoin d'un script "runner" qui, pour chaque module, instancie la classe qui s'y trouve (le nom de la classe peut être construit par le nom du module) et appelle la méthode "go" sur chacun d'entre eux.Meilleure façon de créer un script "runner" en Python?

Je ne sais pas combien de modules sont là, mais je peux énumérer tous englobement le répertoire par quelque chose comme « bot _ *. Py »

Je pense que cela est quelque chose de « programmation méta », mais comment pourrait être la meilleure (la plus élégante) façon de le faire?

Répondre

3
def run_all(path): 
    import glob, os 
    print "Exploring %s" % path 
    for filename in glob.glob(path + "/*.py"): 
     # modulename = "bot_paperino" 
     modulename = os.path.splitext(os.path.split(filename)[-1])[0] 
     # classname = "Paperino" 
     classname = modulename.split("bot_")[-1].capitalize() 
     # package = "path.bot_paperino" 
     package = filename.replace("\\", "/").replace("/", ".")[:-3] 
     mod = __import__(package) 
     if classname in mod.__dict__[modulename].__dict__.keys(): 
      obj = mod.__dict__[modulename].__dict__[classname]() 
      if hasattr(obj, "go"): 
       obj.go() 

if __name__ == "__main__": 
    import sys 
    # Run on each directory passed on command line 
    for path in sys.argv[1:]: 
     run_all(sys.argv[1]) 

Vous avez besoin d'un __init__.py dans chaque chemin que vous voulez "exécuter". Changez "bot_" à votre gré. Exécuter sur Windows et Linux.

4

Vous pouvez utiliser __import__() pour charger chaque module, utilisez dir() pour trouver tous les objets de chaque module, trouver tous les objets qui sont des classes, instancier les et exécuter la méthode go():

import types 
for module_name in list_of_modules_to_load: 
    module = __import__(module_name) 
    for name in dir(module): 
     object = module.__dict__[name] 
     if type(object) == types.ClassType: 
      object().go() 
+0

Utilisé votre utilisation du module types et __dict__ pour modifier ma réponse. Cela rend l'approche beaucoup plus propre et dynamique. – pboucher

1

est ici une façon de le faire du haut de ma tête où je dois présumer la structure de vos modules un peu:

mainDir/ 
    runner.py 
    package/ 
    __init__.py 
    bot_moduleA.py 
    bot_moduleB.py 
    bot_moduleC.py

Dans runner vous pouvez trouver ceci:


import types 
import package 

for moduleName in dir(package): 
    module = package.__dict__[moduleName] 
    if type(module) != types.ModuleType: 
    continue 

    for klassName in dir(module): 
    klass = module.__dict__[klassName] 
    if type(klass) != types.ClassType: 
     continue 
    klass().go() 
1

Je voudrais essayer:

import glob 
import os 

filelist = glob.glob('bot_*.py') 
for f in filelist: 
    context = {} 
    exec(open(f).read(), context) 
    klassname = os.path.basename(f)[:-3] 
    klass = context[klassname] 
    klass().go() 

Cela ne fonctionnera que des classes le même nom au module, qui je pense est ce que vous voulez. Il n'a pas non plus l'exigence du répertoire de premier niveau d'être un paquet.

Attention, glob retourne le chemin complet, y compris les répertoires précédents, d'où l'utilisation de os.path.basename (f) [: - 3] pour obtenir le nom de la classe.

+0

ou 'os.path.splitext (os.path.basename (f)) [0]' (vous ne savez jamais ce que l'avenir réserve aux extensions :) – tzot

Questions connexes