3

I have a text file that contains Python function like this:

a.txt

def func():
    var = 5
    return var

And then I read this file in a Python script:

b.py

python_file = open("a.txt").read()

Now I want to assign the a.txt file's function to a variable without worrying about the function name and execute it. I tried something like this:

python_file = open("a.txt").read()
b = exec(python_file)
b()

But it didn't work, I tried execfile as well.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Ashisha Nautiyal
  • 1,389
  • 2
  • 19
  • 39

2 Answers2

4

After you've executed the string, you can call func directly, as it has been added to your current namespace:

>>> exec("""def func():
    var = 5  # note that the semicolons are redundant and unpythonic
    return var""")
>>> func()
5

Per its documentation exec doesn't actually return anything, so there's no point assigning e.g. foo = exec(...).


To see what names are locally defined in the code being executed, pass an empty dictionary to exec as the locals parameter:

>>> ns = {}
>>> exec("""def func():
    var = 5
    return var""", globals(), ns)
>>> ns
{'func': <function func at 0x0315F540>}

You can then assign the function and call it as you normally would:

>>> b, = ns.values()  # this will only work if only one name was defined
>>> b()
5
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
2

Before offering my solution, I highly warn against do this unless you know for sure there is no malicious code in a.txt.

My solution uses the execfile function to load the text file and return the first object (could be a variable or function):

def load_function(filename):
    """ Assume that filename contains only 1 function """
    global_var = dict()
    execfile(filename, global_var)
    del global_var['__builtins__']
    return next(global_var.itervalues())

# Use it
myfunction = load_function('a.txt')
print myfunction()

Update

To be a little more careful, modify the return line like the following so that it skips variables (it cannot skip class declaration, however).

    return next(f for f in global_var.itervalues() if callable(f))

Update 2

Thank you johnsharpe for pointing out that there is no execfile in Python 3. Here is a modified solution which use exec instead. This time, the function should be found in the "local" scope.

def load_function(filename):
    """ Assume that filename contains only 1 function """
    with open(filename) as f:
        file_contents = f.read()
        global_var = dict()
        local_var = dict()
        exec file_contents in global_var, local_var
        return next(f for f in local_var.itervalues() if callable(f))

# Use it
myfunction = load_function('a.txt')
print myfunction()
Hai Vu
  • 37,849
  • 11
  • 66
  • 93
  • Note that Python 3 doesn't have `execfile`, see e.g. https://docs.python.org/3/whatsnew/3.0.html#builtins, http://stackoverflow.com/q/436198/3001761 – jonrsharpe Aug 10 '15 at 13:34
  • My bad. I don't have Python 3. In that case, your solution (open text file, read contents, call exec) combine with mine (get the first callable from the global name space) will work. – Hai Vu Aug 10 '15 at 13:36