如何在Python中动态加载类和调用方法?

时间:2017-03-15 08:13:25

标签: python python-2.7 class methods

我有一个Python脚本,它将两个用户输入作为命令行参数。第一个用户输入称为load-class,第二个用户输入称为call-method

主Python脚本充当一个所谓的控制器,它可以加载其他(让我们称之为控制器案例)Python脚本,调用这些脚本中的方法并使用该方法返回。这就是操作员无法直接执行控制器案例Python脚本的原因。

以下是非工作示例:

#!/usr/bin/env python

import sys
import argparse
import textwrap

import ControllerCases

parser = argparse.ArgumentParser(
    formatter_class=argparse.RawDescriptionHelpFormatter,
    epilog="{0}".format('-' * 80),
    description=textwrap.dedent('''\
    TODO: Enter Title Here
{0}
  TODO: Enter Info Here
{0}
'''.format('-' * 80))
)

parser.add_argument('--load-class', '-c', type=str, required=True, help="Name of the class.")
parser.add_argument('--call-method',  '-m', type=str, required=True, help="Name of the method within selected class.")

parsed_args = parser.parse_args()

def main(argv):
    print 'Number of arguments:', len(sys.argv), 'arguments.'
    print 'Argument List:', str(sys.argv)
    print 'Load class: ', str(parsed_args.load_class)
    print 'Call method: ',  str(parsed_args.call_method)
    getattr(ControllerCases[parsed_args.load_class], parsed_args.call_method)(argv)

if __name__ == "__main__":
    main(sys.argv[1:])

控制器的Python脚本如下所示:

#!/usr/bin/env python

class dummy():
    def hello(argv):
        print 'Hello World'

ControllerCases文件夹中我有__init__.py

#!/usr/bin/env python

import os
for module in os.listdir(os.path.dirname(__file__)):
    if module == '__init__.py' or module[-3:] != '.py':
        continue
    __import__(module[:-3], locals(), globals())
del module

现在我试图执行控制器,这发生了:

$ python controller.py --load-class dummy --call-method hello
Number of arguments: 5 arguments.
Argument List: ['controller.py', '--load-class', 'dummy', '--call-method', 'hello']
Load class:  dummy
Call method:  hello
Traceback (most recent call last):
  File "controller.py", line 33, in <module>
    main(sys.argv[1:])
  File "controller.py", line 30, in main
    getattr(ControllerCases[parsed_args.load_class], parsed_args.call_method)(argv)
TypeError: 'module' object has no attribute '__getitem__'

我使用的是Python 2.7.13。

如何在Python中动态加载类和调用方法?

1 个答案:

答案 0 :(得分:1)

我通过现实生活中的帮助解决了这个问题。我必须将控制器案例从类转换为模块,并且必须调用getattr两次:一次用于模块,一次用于方法。

通过删除class XYZ():行,将控制器案例类转换为控制器案例模块。

自:

#!/usr/bin/env python

class dummy():
    def hello(argv):
        print 'Hello World'

要:

#!/usr/bin/env python

def hello(argv):
    print 'Hello World'

更改控制器中的getattr代码。

自:

def main(argv):
    print 'Number of arguments:', len(sys.argv), 'arguments.'
    print 'Argument List:', str(sys.argv)
    print 'Load class: ', str(parsed_args.load_class)
    print 'Call method: ',  str(parsed_args.call_method)
    getattr(ControllerCases[parsed_args.load_class], parsed_args.call_method)(argv)

if __name__ == "__main__":
    main(sys.argv[1:])

要:

def main(argv):
    print 'Number of arguments:', len(sys.argv), 'arguments.'
    print 'Argument List:', str(sys.argv)
    print 'Load class: ', str(parsed_args.load_class)
    print 'Call method: ',  str(parsed_args.call_method)
    load_class = getattr(ControllerCases, parsed_args.load_class)
    call_method = getattr(load_class, parsed_args.call_method)
    try:
        call_method(argv)
    except KeyboardInterrupt:
        print 'UserAborted'

if __name__ == "__main__":
    main(sys.argv[1:])