Динамическое добавление функций в класс

#python #function #dynamic

#python #функция #динамический

Вопрос:

Я динамически добавляю функции в class ( A ) с некоторыми переменными ( my_name ). Но когда я вызываю функции в class ( A ), я получаю правильную функцию (правильное имя функции), но с переменными из последней функции. Как динамически устанавливать переменные в функции или как решить подобную проблему?

 class A:
    pass


function_name_list = ['first/function', 'second/function', 'third/function']


def add_method(cls, fnctname):
    def decorator(func):
        @wraps(func)
        def wrapper(self, *args, **kwargs):
            return func(*args, **kwargs)

        setattr(cls, fnctname, wrapper)
        return func

    return decorator


def create_functions():
    for x in function_name_list:
        name = x.replace('/', '')

        @add_method(A, name)
        def foo(value):
            my_name = copy.deepcopy(name)
            with open('./file'   str(my_name)   '.txt', 'a') as f:
                f.write(str(time.time())   ','   my_name   ','   str(value)   "n")
                print('Call: ', my_name)


a = A()
create_functions()

for x in function_name_list:
    name = x.replace('/', '')
    getattr(a, '%s' % name)(1)
  

Ответ №1:

Внутри вашего create_function , def foo() привязывается к переменной name . Он получит текущее значение name при вызове функции. Существует только одна name переменная, поэтому все ваши foo функции привязаны к одной и той же переменной.

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

 def create_functions():
    for x in function_name_list:
        create_foo(x.replace('/', ''))

def create_foo(name):
        @add_method(A, name)
        def foo(value):
            with open('./file'   str(name)   '.txt', 'a') as f:
                f.write(str(time.time())   ','   name   ','   str(value)   "n")
                print('Call: ', name)
  

( copy.deepcopy() на a str вернет оригинал str , поэтому я его удалил.)

Гораздо более простой метод — просто связать аргументы с помощью functools.partial :

 import functools

def foo(self, value, name):
    with open('./file'   str(name)   '.txt', 'a') as f:
        f.write(str(time.time())   ','   name   ','   str(value)   "n")
        print('Call: ', name)

def create_functions():
    for x in function_name_list:
        name = x.replace('/', ''))
        setattr(A, name, functools.partial(foo, name=name))