Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

return variable name from outside of function, as string inside python function

So I have created a function that applies an action (in this case point wise multiplication of an array with a sinusoid, but that does not matter for my question) to an array.

Now I have created another function with which I want to create a string of python code to apply the first function multiple times later-on. The input of the second function can be either a string or an array, so that I can use the second function on its own output as well, if need be. My method of getting the variable name in a string works outside of the function.

Input :

var = np.array([[1,3],[2,4]]) # or sometimes var = 'a string'

if type(var)==str:
    var_name = var
else:
    var_name = [ k for k,v in locals().items() if v is var][0]

var_name

Output :

'var'

So here var is the variable (either array or string) supplied to the function, in this case an array. The if statement nicely returns me its name.

However when I use this inside my function, no matter what input I give it, it actually seems to look for var in locals(). Somehow it does not take var from the function input.

Definition :

def functionTWO(var, listoflistsofargs=None):
    if type(var)==str:
        var_name = var
    else:
        var_name = [ k for k,v in locals().items() if v is var][0]
    if listoflistsofargs==None:
        return var_name
    command = []
    for i in range(len(listoflistsofargs)):
        if i==0:
            command.append('functionONE(')
            command.append(var_name)
            command.append(',%.17f, %.17f)' % tuple(listoflistsofargs[i]))
        else:
            command.insert(0,'functionONE(')
            command.append(',%.17f, %.17f)' % tuple(listoflistsofargs[i]))
    ''.join(command)
    command[0] = var_name + ' + ' + command[0]
    return ''.join(command)

Input :

somearray = np.array([[1,2,3],[1,2,3],[1,2,3]])
args = [[1,3],[6,5]]
command = functionTWO(somearray, args)
command

Output :

NameError: name 'var' is not defined

Wanted output :

'functionONE(functionONE(somearray, 1, 3), 6, 5)'

Why is listoflistsofargs taken from the function input and var not? I specify var in the listcomprehension in the definition of functionTWO. Normally when I use list comprehensions with function inputs it works fine. Does anybody know why this isnt the case here? Thank you in advance!

EDIT : So I guess the answer is dont. The implementation of classes by Marcin looks much cleaner and about the same order of amount of code. Too bad I couldnt get this to work inside a function. For other donts (actually other ideas) about using variable names as strings there is this question, where I got the above list comprehension for variable names.

like image 959
Leo Avatar asked Jun 17 '26 19:06

Leo


1 Answers

You cannot pass a variable as a string*, and you should not do so.

If you want to pass a value between functions, the normal way is to pass it in as a parameter, and out as a return value.

If that is inconvenient, the usual solution is an object: define a class which carries both the shared variable, and methods which act on the variable.

If you need to create command objects, it is much better to do so in a structured way. For example, if you want to pass a function, and parameters, you can literally just pass the function object and the parameters in a tuple:

def foo():
    return (functionONE,somearray,1,3)

command = foo()
command[0](*command[1:])

If you want to embed such commands within commands, you'll likely want to wrap that up with a class, so you can recursively evaluate the parameters. In fact, here's a little evaluator:

def evaluator(object):
    def __init__(self,func=None,params=None):
        self.func = func
        self.params = params

    def eval(self,alternativeparams=None):
        if alternativeparams is not None:
           params = alternativeparams
        else:
           params = self.params

        if params is not None:
           evaluatedparams = (item() if callable(item) else item for item in params)
        else: evaluatedparams = None

        if func is not None:
           return self.func(*(evaluatedparams or ()))
        else: return evaluatedparams
    def __call__(self, *params):
        return self.eval(params if params else None)

Although there are hacks by which you can pass references to local variables out of a function, these are not a great idea, because you end up creating your own half-baked object system which is more difficult to understand.

* This is because a variable has a name (which is a string) and a context, which maps names to strings. So, you need, at least to pass a tuple to truly pass a variable.

like image 195
Marcin Avatar answered Jun 19 '26 09:06

Marcin