2009-01-23 229 views
3

我在一個目錄中有一堆Python模塊,都是派生類。我需要一個「runner」腳本,爲每個模塊實例化其中的類(實際的類名可以通過模塊文件名構建),並在每個模塊上調用「go」方法。在Python中創建「runner」腳本的最佳方式是什麼?

我不知道有多少模塊是有的,但我可以列出所有的人都通過的東西通配符的目錄,如「機器人_ *。PY」

我認爲這是一些有關「元編程」,但怎麼可能是最好的(最優雅的)方法呢?

回答

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上運行。

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

使用您使用的類型模塊和__dict__來修改我的答案。這使得更清潔和動態的方法。 – pboucher 2009-01-23 18:58:45

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() 
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]來獲取類名。

+0

或`os.path.splitext(os.path.basename(f))[0]`(你永遠不知道未來對擴展名有什麼影響:) – tzot 2010-05-16 21:45:52

相關問題