Как динамически создавать функции модуля, функции из методов в классе

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

  •  01-10-2019
  •  | 
  •  

Вопрос

Я пытаюсь динамически создавать функции модуля функций из методов в классе. Таким образом, для каждого метода в классе я хочу создать функцию с тем же именем, что создает экземпляр класса, а затем вызывает метод.

Причина, по которой я хочу сделать это, это так, что я могу принять объектно-ориентированный подход к созданию файлов ткани. Поскольку ткань будет вызывать функции уровня модуля, но не методы класса, это моя работа - вокруг.

Я использовал следующие ссылки, чтобы заставить меня начаться

И я придумал следующий код

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__', <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)

Похоже, это воссматривает ссылку на функцию? Есть идеи?

Обновление: вот рабочий код с исправлением 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-fabrich-scrippts-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, является вызываемой вещью. Просто назначьте его своему атрибуту модуля, и вы хотите пойти.

Другие советы

На самом деле ваш код прав, но при возврате функции func (* args, ** kwargs), args пройдет пустой кортеж как (), и нет параметров в вашем методе2, поэтому он поднимает такое исключение,

Быстрый раствор по вашей проблеме будет, как

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

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

    def method2(self, *args, **kw):
        print 'method 2'
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top