J'essaie de créer dynamiquement des fonctions de niveau module à partir des méthodes d'une classe. Donc, pour chaque méthode dans une classe, je veux créer une fonction avec le même nom qui crée une instance de la classe, puis appelle la méthode.Comment créer dynamiquement des fonctions de niveau module à partir des méthodes d'une classe
La raison pour laquelle je veux faire ceci est que je peux adopter une approche orientée objet pour créer des fichiers Fabric. Puisque Fabric appellera des fonctions de niveau de module mais pas des méthodes d'une classe, c'est mon work-around.
J'ai utilisé les liens suivants pour me commencé
- How do I get list of methods in a Python class?
- dynamically adding functions to a Python module
- How do I call setattr() on the current module?
- http://effbot.org/zone/python-getattr.htm
- Calling a function of a module from a string with the function's name in Python
- How to modify the local namespace in python
Et je suis venu avec le code suivant
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()
et je reçois l'erreur suivante
['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)
Il semble réutiliser la référence à la fonction? Des idées?
MISE À JOUR: Voici le code de travail avec la solution de 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)
MISE À JOUR 2: Voici mon blog sur le sujet: http://www.saltycrane.com/blog/2010/09/class-based-fabric-scripts-metaprogramming-hack/
bizarrement, vous devez également définir 'func .__ module__ = nom_module' pour qu'il se décrive correctement ... sinon il signalera son module comme celui contenant' fabric_class_to_function_magic' au lieu du module cible! – F1Rumors