0

As a follow-up to this question I asked earlier, I'm experimenting with executing Python code as if it were in the context of an outer function. I do this by simply wrapping a block of code with def outer():, and doing some simple string processing to properly indent the inner code. Then I compile it and execute the compiled inner code by executing the first code object in the co_consts list.

Example:

mycode = """
print("Hey!")
"""

wrapped_code = 'def outer():\n    ' + '\n    '.join(mycode.strip().split('\n'))
compiled_code = compile(wrapped_code, '<str>', 'exec')
exec(compiled_code.co_consts[0], {}, {})

This executes the code print("Hey") from within the context of an outer function. (If anyone is wondering why I'm doing this, it's part of a C extension module I've been working on.)

Question: A problem I run into is that if I wrap code in an outer function, and then execute the inner block of code, I don't seem to be able to pass any local variables to the execution context.

mycode = """
print(locals())
"""

wrapped_code = 'def outer():\n    ' + '\n    '.join(mycode.strip().split('\n'))
compiled_code = compile(wrapped_code, '<str>', 'exec')
exec(compiled_code.co_consts[0], {}, {"foo" : "bar"})

This outputs:

{}

Notice that I explicitly passed a local dict containing {"foo" : "bar"} to exec, yet when it actually executes the code and prints locals(), it shows an empty dictionary. Why didn't Python use the dictionary of local variables I passed it?

Community
  • 1
  • 1
Channel72
  • 24,139
  • 32
  • 108
  • 180
  • 1
    "If anyone is wondering why I'm doing this, it's part of a C extension module I've been working on." - That doesn't answer the question. No extension module I've ever seen does this. – Lennart Regebro Apr 01 '13 at 10:37
  • 1
    See [Include/code.h](http://hg.python.org/cpython/file/bd8afb90ebf2/Include/code.h#l35) and [Objects/frameobject.c](http://hg.python.org/cpython/file/bd8afb90ebf2/Objects/frameobject.c#l693) (`PyFrame_New`, 693-710). – Eryk Sun Apr 01 '13 at 12:42
  • @eryksun, thanks. Your comment solved my problem. All I needed to do was set the `co_flags` variable in the function code object to `0`, so it would use the locals dictionary I passed it, rather than create a new local dictionary for the execution frame. – Channel72 Apr 02 '13 at 18:28

1 Answers1

0

You are passing in a function as the first parameter to exec. A function will define it's own locals, so that's the locals you are printing. Remove the wrapping (which I can't see any use of whatsoever) and it works.

Lennart Regebro
  • 167,292
  • 41
  • 224
  • 251
  • Is there a way to access/manipulate the function local dictionary? – Channel72 Apr 01 '13 at 11:06
  • @Channel72: From outside the function, no. Because it's local. You are barking up the wrong tree, and should post a question about the problem you are actually trying to solve by using exec(). You almost never need to use exec(). – Lennart Regebro Apr 01 '13 at 11:21