我有一个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中动态加载类和调用方法?
答案 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:])