Wie dynamisch Modulebene Funktionen von Methoden in einer Klasse erstellen
-
01-10-2019 - |
Frage
Ich versuche, dynamisch Funktionen Modulebene von den Methoden in einer Klasse zu erstellen. So für jede Methode in einer Klasse, ich mag eine Funktion mit dem gleichen Namen erstellen, die eine Instanz der Klasse erstellt und ruft dann die Methode.
Der Grund, warum ich dies tun wollen ist, damit ich einen objektorientierter Ansatz zur Schaffung von Fabric-Dateien nehmen. Da Fabric-Modul-Level-Funktionen aufrufen, aber nicht Methoden einer Klasse, das ist meine Work-around.
Ich habe die folgenden Links verwendet, um mich zu erhalten begonnen
- Wie erhalte ich Liste der Methoden in einer Python-Klasse?
- dynamisch Funktionen zu einem Python-Modul hinzugefügt
- Wie rufe ich setattr () auf dem aktuellen Modul ?
- http://effbot.org/zone/python-getattr.htm
- Aufrufen einer Funktion eines Modul aus einer Zeichenfolge mit dem Namen der Funktion in Python
- Wie der lokalen Namensraum ändern in Python
Und ich habe kommen mit dem folgenden Code
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()
Und ich bekomme die folgende Fehlermeldung
['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)
Es scheint, den Verweis auf die Funktion zu Wiederverwendung? Irgendwelche Ideen?
UPDATE: Hier ist der Arbeits Code mit Ned Batchelder ist fix
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)
UPDATE 2: Hier ist meine Blog-Post auf dem Betreff: http://www.saltycrane.com/blog/2010/09/class-based-fabric-scripts-metaprogramming-hack/
Lösung
Sie überdenken Ihre Lösung. Ändern Sie das Ende fabric_class_to_function_magic
zu sein, dies:
tc = TestClass()
func = getattr(tc, method_name)
# add the new function to the current module
setattr(module_obj, method_name, func)
und es funktioniert gut. Keine Notwendigkeit, ein neues Funktionsobjekt zu machen, haben Sie bereits eine von getattr auf Ihrem Objekt zurückgegeben. Die gebundene Methode von getattr zurückgegeben wird, ist eine aufrufbare Sache. Nur ordnen Sie es Ihr Modul Attribut, und Sie sind gut zu gehen.
Andere Tipps
tatsächlich Code ist richtig, aber wenn Rückkehr func (* args, ** kwargs) ausgeführt wird, wird args leere Tupel übergeben wie (), und es sind keine Parameter in Ihrem method2, so dass es eine solche Ausnahme auslöst,
eine schnelle Lösung zu Ihrem Problem wäre, wie
class TestClass(object):
def __init__(self):
pass
def method1(self, arg1):
print 'method 1 %s' % arg1
def method2(self, *args, **kw):
print 'method 2'