我试图从类中的方法动态创建模块级函数.因此,对于类中的每个方法,我想创建一个具有相同名称的函数,该函数创建类的实例,然后调用该方法.
我想这样做的原因是我可以采用面向对象的方法来创建Fabric文件.由于Fabric将调用模块级函数而不是类的方法,因此这是我的解决方法.
我使用以下链接让我开始
如何获取Python类中的方法列表?
动态添加函数到Python模块
如何在当前模块上调用setattr()?
http://effbot.org/zone/python-getattr.htm
在Python中使用函数名称从字符串调用模块的函数
如何在python中修改本地命名空间
我提出了以下代码
import inspect import sys import types class TestClass(object): def __init__(self): pass def method1(self, arg1): print 'method 1 %s' % arg1 def method2(self): print 'method 2' def fabric_class_to_function_magic(module_name): # get the module as an object print module_name module_obj = sys.modules[module_name] print dir(module_obj) # Iterate over the methods of the class and dynamically create a function # for each method that calls the method and add it to the current module for method in inspect.getmembers(TestClass, predicate=inspect.ismethod): print print method method_name, method_obj = method # create a new template function which calls the method def newfunc_template(*args, **kwargs): tc = TestClass() func = getattr(tc, method_name) return func(*args, **kwargs) # create the actual function print 'code: ', newfunc_template.func_code print 'method_name: ', method_name newfunc = types.FunctionType(newfunc_template.func_code, {'TestClass': TestClass, 'getattr': getattr, 'method_name': method_name, }, name=method_name, argdefs=newfunc_template.func_defaults, closure=newfunc_template.func_closure, ) # add the new function to the current module setattr(module_obj, method_name, newfunc) # test the dynamically created module level function thismodule = sys.modules[__name__] print dir(thismodule) fabric_class_to_function_magic(__name__) print dir(thismodule) method1('arg1') method2()
我收到以下错误
['TestClass', '__builtins__', '__doc__', '__file__', '__name__', '__package__', 'fabric_class_to_function_magic', 'inspect', 'sys', 'thismodule', 'types'] __main__ ['TestClass', '__builtins__', '__doc__', '__file__', '__name__', '__package__', 'fabric_class_to_function_magic', 'inspect', 'sys', 'thismodule', 'types'] ('__init__',) code: method_name: __init__ ('method1',
) code: method_name: method1 ('method2',
) code: method_name: method2 ['TestClass', '__builtins__', '__doc__', '__file__', '__init__', '__name__', '__package__', 'fabric_class_to_function_magic', 'inspect', 'method1', 'method2', 'sys', 'thismodule', 'types'] Traceback (most recent call last): File "test.py", line 111, in
method1('arg1') File "test.py", line 88, in newfunc_template return func(*args, **kwargs) TypeError: method2() takes exactly 1 argument (2 given)
它似乎重用了函数的引用?有任何想法吗?
更新:这是Ned Batchelder修复的工作代码
def fabric_class_to_function_magic(module_name): # get the module as an object module_obj = sys.modules[module_name] # Iterate over the methods of the class and dynamically create a function # for each method that calls the method and add it to the current module for method in inspect.getmembers(TestClass, predicate=inspect.ismethod): method_name, method_obj = method # get the bound method tc = TestClass() func = getattr(tc, method_name) # add the function to the current module setattr(module_obj, method_name, func)
更新2:这是我关于这个主题的博客文章:http://www.saltycrane.com/blog/2010/09/class-based-fabric-scripts-metaprogramming-hack/
你过分思考你的解决方案.改变结尾为fabric_class_to_function_magic
:
tc = TestClass() func = getattr(tc, method_name) # add the new function to the current module setattr(module_obj, method_name, func)
它工作正常.无需创建新的函数对象,您的对象上已经有getattr返回的函数对象.getattr返回的绑定方法是可调用的东西.只需将其分配给您的模块属性,就可以了.