0

I'm dynamically adding functions in class (A) with some variables (my_name). But when I call functions in class (A) I get correct function (correct name of function) but with variables from last function. How to dynamically set variables in function or how to solve problem like this?

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 Answer 1

1

Inside your create_function, def foo() binds to the variable name. It will pick up the current value of name when the function is called. There is only one name variable so all of your foo functions are bound to the same variable.

If you really want to do this you must ensure there is a separate variable bound to each function. Pull the entire body of your for loop out to a separate function then it will create different variables for each function.

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() on a str will return the original str so I removed it.)

A much simpler technique is just to bind arguments using 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))
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.