Лучший способ создать скрипт "бегуна" в Python? - PullRequest
3 голосов
/ 23 января 2009

У меня есть несколько модулей Python в каталоге, каждый из которых является производным классом. Мне нужен скрипт "runner", который для каждого модуля создает экземпляр класса внутри него (фактическое имя класса может быть построено по имени файла модуля) и затем вызывает метод "go" для каждого из них.

Я не знаю, сколько там модулей, но я могу перечислить все из них, перетаскивая каталог через что-то вроде "bot _ *. Py"

Я думаю, что это что-то о «метапрограммировании», но как может быть лучший (самый элегантный) способ сделать это?

Ответы [ 4 ]

4 голосов
/ 23 января 2009

Вы можете использовать __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()
3 голосов
/ 23 января 2009
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.

1 голос
/ 23 января 2009

Я бы попробовал:

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], чтобы получить имя класса.

1 голос
/ 23 января 2009

Вот один из способов сделать это из головы, где я должен немного предположить структуру ваших модулей:

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

В Runner вы можете найти это:


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