Comment créer dynamiquement des fonctions de niveau du module de méthodes dans une classe

StackOverflow https://stackoverflow.com/questions/3664302

  •  01-10-2019
  •  | 
  •  

Question

Je suis en train de créer dynamiquement des fonctions de niveau du module des méthodes dans une classe. Ainsi, 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.

La raison pour laquelle je veux faire est que je puisse adopter une approche orientée objet pour la création de fichiers tissu. Depuis Fabric appeler des fonctions au niveau du module, mais pas les méthodes d'une classe, c'est mon travail autour.

Je l'ai utilisé les liens suivants pour me commencé

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? Toutes les 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/

Était-ce utile?

La solution

Vous êtes trop penser à votre solution. Changer la fin de fabric_class_to_function_magic être ceci:

    tc = TestClass()
    func = getattr(tc, method_name)

    # add the new function to the current module
    setattr(module_obj, method_name, func)

et il fonctionne très bien. Pas besoin de faire un nouvel objet de fonction, vous avez déjà un retourné par getattr sur votre objet. La méthode liée retourné par getattr est une chose appelable. Il suffit de l'attribuer à votre attribut de module, et vous êtes bon pour aller.

Autres conseils

en fait votre code est bon, mais lorsque le retour func (* args, ** kwargs) exécute, args passeront tuple vide comme () et il n'y a pas de paramètres dans votre method2, il soulève une telle exception,

une solution rapide à votre problème serait, comme

class TestClass(object):
    def __init__(self):
        pass

    def method1(self, arg1):
        print 'method 1 %s' % arg1

    def method2(self, *args, **kw):
        print 'method 2'
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top