3

我在一个目录中有一堆 Python 模块,它们都是派生类。我需要一个“运行器”脚本,对于每个模块,实例化其中的类(实际的类名可以由模块文件名构建),然后在每个模块上调用“go”方法。

我不知道那里有多少模块,但我可以通过“bot_*.py”之类的方式列出所有模块

我认为这是关于“元编程”的东西,但怎么可能是最好(最优雅)的方式呢?

4

4 回答 4

4

您可以使用__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()
于 2009-01-23T18:43:50.473 回答
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])

你需要__init__.py在你想要“运行”的每条路径中都有一个。随意更改“bot_”。在 windows 和 linux 上运行。

于 2009-01-23T20:00:25.327 回答
1

这是我想到的一种方法,我必须稍微假设一下模块的结构:

主目录/
  跑步者.py
  包裹/
    __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()
于 2009-01-23T18:49:37.450 回答
1

我会尝试:

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] 来获取类名。

于 2009-01-23T19:35:36.607 回答