18

In Python, I have a string of some Python source code containing functions like:

mySrc = '''
def foo():
    print("foo")

def bar():
    print("bar")
'''

I'd like to compile this string into some kind of module-like object so I can call the functions contained in the code.

Here's pseudo-code for what I'd like to do:

myMod = myCompile(mySrc)
myMod.foo()

Is this possible in Python? I've tried this, but it does not work:

myMod = compile(mySrc, '', 'exec')
myMod.foo()

This produces an error message like this:

<code object <module> at 0x104154730, file "", line 1>Traceback (most recent call last):
  File "myfile.py", line XX, in run
    myMod.foo()
AttributeError: 'code' object has no attribute 'foo'
0

2 Answers 2

28

You have to both compile and execute it:

myMod = compile(mySrc, '', 'exec')
exec(myMod)
foo()

You can pass dicts to exec to stop foo from “leaking” out. Combine it with a module object created using types.ModuleType:

from types import ModuleType
…
compiled = compile(mySrc, '', 'exec')
module = ModuleType("testmodule")
exec(compiled, module.__dict__)
Sign up to request clarification or add additional context in comments.

1 Comment

The second option listed here is especially helpful, because: If the source code string contains import statements, the second option listed here executes them and allows the rest of the source code in the string to use symbols/objects thus imported. AFAICT, that is not the case in the first option. (I should have mentioned this requirement in my initial question, but your excellent/detailed answer here provided the info I needed anyway. Perfect.)
1

In Python 2, you want the magical compiler package:

>>> import compiler
>>> mod = compiler.parseFile("doublelib.py")
>>> mod
Module('This is an example module.\n\nThis is the docstring.\n',
       Stmt([Function(None, 'double', ['x'], [], 0,
                      'Return twice the argument',
                      Stmt([Return(Mul((Name('x'), Const(2))))]))]))
>>> from compiler.ast import *
>>> Module('This is an example module.\n\nThis is the docstring.\n',
...    Stmt([Function(None, 'double', ['x'], [], 0,
...                   'Return twice the argument',
...                   Stmt([Return(Mul((Name('x'), Const(2))))]))]))
Module('This is an example module.\n\nThis is the docstring.\n',
       Stmt([Function(None, 'double', ['x'], [], 0,
                      'Return twice the argument',
                      Stmt([Return(Mul((Name('x'), Const(2))))]))]))
>>> mod.doc
'This is an example module.\n\nThis is the docstring.\n'
>>> for node in mod.node.nodes:
...     print node
...
Function(None, 'double', ['x'], [], 0, 'Return twice the argument',
         Stmt([Return(Mul((Name('x'), Const(2))))]))
>>> func = mod.node.nodes[0]
>>> func.code
Stmt([Return(Mul((Name('x'), Const(2))))])

And in Python 3, it's built right in.

3 Comments

Thanks, this is very interesting. But I have my source code in an in-memory string (not in a file on disk). In this case I will also prefer to use a very high-level solution like the answer above. Very good to learn about this, tho. Will be useful. :)
In Py2, it's just compiler.parse for an in-memory string, instead of parseFile. In Python 3, I believe you just use compile() and pass something like '<string>' as the filename.
@KenKinder Yeah, but then what? Pass it to exec, right? exec returns None, where's the module?

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.