Setting function variables with execfile()

5.1k views Asked by At

I am trying to load information into a user defined function for further processing. Since the input files must be generated by non-programmers I have chosen the following format:

#contents of vessel_data.txt
hull_length = 100000.
hull_width  = 50000.
etc.

My function then loads the input file via execfile(). I then want to group data into an array and pass that as the output of the function. Roughly like so:

file_path = ..\vessel_name.txt

def my_input_func(file_path):
    execfile(file_path)

    data = np.array([[hull_length],
                     [hull_width ],
                     [etc.       ]])

    return(data)

I know that loading data via exec() and execfile() are frowned upon, but bear in mind that the input are generated by non-programmers. Anyways, I get the following error:

NameError: global name 'hull_length' is not defined

After adding these lines, I can confirm that my variables are loaded into the local name space as expected:

print 'Locals:  ' + str([x for x in locals()  if x[0] == 'h'])
print 'Globals: ' + str([x for x in globals() if x[0] == 'h'])

What puzzles me is why my function looks to the global name space when I try to define my variables. I were under the impression that unless specifically stated, everything inside a function dealt with the name space local to the function. I can make it work by modifying my execfile() command to:

execfile(file_path, globals())

but I am not interested in loading everything into the global name space.

So, how do I make this work without loading everything into the global name space?

Kind regards, Rasmus

======== Edit =======

This is how I made it work based on Quentin's answer:

file_path = ..\vessel_name.txt

def my_input_func(file_path):
    vessel_vars = {}
    execfile(file_path, vessel_vars)

    data = np.array([[vessel_vars['hull_length']],
                     [vessel_vars['hull_width'] ],
                     [vessel_vars['etc.']       ]])

    return(data)

Cheers Quentin!

1

There are 1 answers

0
Quentin Pradet On BEST ANSWER

The docs for execfile() warn about wanting to modify a function local variables: it's not possible!

The default locals act as described for function locals() below: modifications to the default locals dictionary should not be attempted. Pass an explicit locals dictionary if you need to see effects of the code on locals after function execfile() returns. execfile() cannot be used reliably to modify a function’s locals.

It's not about execfile() but about locals():

def f():
   locals()['a'] = 3
   print(a)

You will also get NameError: global name 'a' is not defined. This is possibly for optimization purposes. The solution here is to use a dictionary:

file_path = os.path.join('..', 'vessel_name.txt')

def my_input_func(file_path):
    vessel = {}
    execfile(file_path, vessel)

    data = np.array([[vessel['hull_length']],
                     [vessel['hull_width'],
                     [vessel['etc.']])

    return(data)

Note: I 'm assuming that you're using Python 2 but it would be the same in Python 3, except that execfile() is now exec() and you need to open the file yourself.