Skip to content

Instantly share code, notes, and snippets.

@cowlicks
Created May 15, 2014 20:20
Show Gist options
  • Select an option

  • Save cowlicks/1d7ef6e66a50ffeceab6 to your computer and use it in GitHub Desktop.

Select an option

Save cowlicks/1d7ef6e66a50ffeceab6 to your computer and use it in GitHub Desktop.
Why doesn't eval work here?
In [11]: def foo():
....: return b
....:
In [12]: eval('foo()', dict({'b':42}, **globals()))
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-12-a2089cf14959> in <module>()
----> 1 eval('foo()', dict({'b':42}, **globals()))
<string> in <module>()
<ipython-input-11-36533771d987> in foo()
1 def foo():
----> 2 return b
3
NameError: global name 'b' is not defined
@cowlicks
Copy link
Copy Markdown
Author

What happens above is:

  • eval sees foo() and gets foo from the eval globals to execute it.
  • foo is called. So foo looks for b in its loclas, not there, then in foo.__globals__ (not in the eval globals).
  • foo.__globals__ refers to the namespace foo was defined in, which does not have b. So NameError is raised.

First I tried to fix this by monkeypatching foo.__globals__. But this is a read only attribute.

What I eventually did is deconstruct foo and rebuild it with a modified globals using the types module. The result is below.

In [1]: def foo():
   ...:     print(b)
   ...:     

In [2]: import types

In [3]: new_foo = types.FunctionType(foo.__code__, dict({'b': 666}, **foo.__globals__), foo.__name__)

In [4]: new_foo()
666

Note eval('new_foo') returns 666 as expected!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment