Динамически добавлять функции в классе - PullRequest
0 голосов
/ 15 апреля 2019

Я динамически добавляю функции в класс (A) с некоторыми переменными (my_name). Но когда я вызываю функции в классе (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 Ответ

1 голос
/ 15 апреля 2019

Внутри вашего create_function, def foo() связывается с переменной name.При вызове функции будет получено значение current , равное 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() на 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))
...