我在目录中有一堆Python模块,都是派生类。我需要一个“runner”脚本,对于每个模块,实例化其中的类(实际的类名可以由模块文件名构建),而不是在每个模块上调用“go”方法。
我不知道有多少个模块,但我可以列出所有这些模块通过像“bot _ *。py”
之类的东西来整理目录。我认为这是关于“元编程”的东西,但怎么可能是最好(最优雅)的方式呢?
答案 0 :(得分: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()
答案 1 :(得分: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上运行。
答案 2 :(得分:1)
这是一种方法来做到这一点,我必须假设你的模块的结构:
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()
答案 3 :(得分: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]来获取类名。