Problem with exec('{} = thisTrial[paramName]'.format(paramName))

This is a strange problem. When I try to get the short names for my variables (one of them is called ‘cond’ for example) the line that works in v1.85.6 works also in v3.0.7 only when it is NOT inside a function.

For example this works (in a for loop just to keep the indentation structure)

for i in [1,2]:
    for thisTrial in trials:
        if thisTrial!=None:
            for paramName in thisTrial.keys():
                exec('{} = thisTrial[paramName]'.format(paramName))
        print(cond)

but this gives me the error below

def runExp():
    for thisTrial in trials:
        if thisTrial!=None:
            for paramName in thisTrial.keys():
                exec('{} = thisTrial[paramName]'.format(paramName))
        print(cond)

NameError: name ‘cond’ is not defined

I don’t understand what is going on.
I am using PsychoPy3 v3.0.7 on a Mac.

Hi @Marco.Bertamini, it is hard to tell without seeing the context. It suggests that the conditions file that contains your “cond” variable has not been loaded at the point you are attempting to access your params.

Are you using Builder or Coder? In Builder, the variables from your conditions file are available by name for each trial without having to create them yourself. After the trial handler has loaded your conditions file, you could just write print(cond) and the value stored for that trial will be accessible during your loop. EDIT: Because the above code is used

Hi, thanks. I am in the coder. The variable is loaded and can be accessed with thisTrial[“cond”] without problems, so it is the shortening of the names that is not working (and only within a function).

Hi Marco (love your PsychoPy illusions book by the way!),

This seems to be a scoping issue that I admit I don’t really understand, but hopefully this SO answer about explicitly setting the scope of the exec function will help:

2 Likes

Hi Michael, thanks for the help (and glad you liked the book)!
It was indeed a scoping issue and your link solved the problem.
So I needed to replace
exec('{} = thisTrial[paramName]'.format(paramName))
with
exec('{} = thisTrial[paramName]'.format(paramName), locals(), globals())

Maybe there is a more elegant solution, but in the meantime this may help other people. This problem only emerged when moving from Python2 to Python3, so other people may experience this.

As the linked page says " if you call exec with one argument, you’re not supposed to try to assign any variables, and Python doesn’t promise what will happen if you try." Worth knowing.

2 Likes