在Python中创建“runner”脚本的最佳方式是什么?

问题描述:

我在一个目录中有一堆Python模块,都是派生类。我需要一个“runner”脚本,为每个模块实例化其中的类(实际的类名可以通过模块文件名构建),并在每个模块上调用“go”方法。在Python中创建“runner”脚本的最佳方式是什么?

我不知道有多少模块是有的,但我可以列出所有的人都通过的东西通配符的目录,如“机器人_ *。PY”

我认为这是一些有关“元编程”,但怎么可能是最好的(最优雅的)方法呢?

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]) 

需要在每个路径的__init__.py要“跑”。 根据您的意愿更改“bot_”。 在windows和linux上运行。

你可以使用__import__()加载每个模块,使用dir()找到每个模块中的所有对象,发现这是类的所有对象,实例化它们,并运行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

使用您使用的类型模块和__dict__来修改我的答案。这使得更清洁和动态的方法。 – pboucher 2009-01-23 18:58:45

这里有一种方法要做到这一点从我的头顶,我必须假设你的模块的结构位:

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

在亚军你会发现这一点:


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

我会尝试:

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

这只会办班同样命名的模块,我认为这是你想要的。它也没有要求顶级目录成为一个包。

要注意,glob返回完整的路径,包括前面的目录,因此使用os.path.basename(f)[: - 3]来获取类名。

+0

或`os.path.splitext(os.path.basename(f))[0]`(你永远不知道未来对扩展名有什么影响:) – tzot 2010-05-16 21:45:52