How to dynamically create module level functions from methods in a class
我正在尝试从类中的方法动态创建模块级函数。因此,对于类中的每个方法,我希望创建一个同名的函数,该函数创建类的一个实例,然后调用该方法。
我之所以要这样做,是因为我可以采用面向对象的方法来创建结构文件。由于结构将调用模块级函数而不是类的方法,所以这是我的工作。
我已使用以下链接开始
- 如何获取Python类中的方法列表?
- 向python模块动态添加函数
- 如何在当前模块上调用setattr()?
- http://effbot.org/zone/python-getattr.htm网站
- 从字符串中调用模块的函数,该字符串的函数名为python
- 如何在python中修改本地命名空间
我想出了以下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | 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 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() |
我得到以下错误
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ['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__', <unbound method TestClass.__init__>) code: <code object newfunc_template at 0x7f8800a28d50, file"test.py", line 85> method_name: __init__ ('method1', <unbound method TestClass.method1>) code: <code object newfunc_template at 0x7f8800a28d50, file"test.py", line 85> method_name: method1 ('method2', <unbound method TestClass.method2>) code: <code object newfunc_template at 0x7f8800a28d50, file"test.py", line 85> 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 <module> method1('arg1') File"test.py", line 88, in newfunc_template return func(*args, **kwargs) TypeError: method2() takes exactly 1 argument (2 given) |
它似乎在重用对函数的引用?有什么想法吗?
更新:这是NedBatchelder的修复程序的工作代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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/
你想得太多了。将EDOCX1[0]的结尾改为:
1 2 3 4 5 | tc = TestClass() func = getattr(tc, method_name) # add the new function to the current module setattr(module_obj, method_name, func) |
而且效果很好。不需要创建新的函数对象,getattr已经在您的对象上返回了一个函数对象。getattr返回的绑定方法是可调用的。只需将其分配给模块属性,就可以开始了。
实际上,您的代码是正确的,但是当返回func(*args,**kwargs)执行时,args将传递类似()的空元组,并且方法2中没有参数,因此它会引发这样的异常,
对于你的问题,一个快速的解决方法是
1 2 3 4 5 6 7 8 9 | class TestClass(object): def __init__(self): pass def method1(self, arg1): print 'method 1 %s' % arg1 def method2(self, *args, **kw): print 'method 2' |