pythonscopeeval

How can I run eval() in the local scope of a function


I try to use eval() in a local scope of a function. However it always evaluate in the global scope.

Self contained examples:

1- This code works:

var1 = 1
var2 = 2
var3 = 3    
myDict = dict((name, eval(name)) for name in ["var1",
                                              "var2",
                                              "var3"])
print(myDict["var1"])

2- Throws NameError for lvar1

def test1():
   lvar1 = 1
   lvar2 = 2
   lvar3 = 3
   myDict = dict((name, eval(name)) for name in ["lvar1",
                                                 "lvar2",
                                                 "lvar3"])
   print(myDict["lvar1"])

3- Same outcome as 2.

def test2():
    lvar1 = 1
    lvar2 = 2
    lvar3 = 3
    myDict = dict((name, eval(name), locals()) for name in ["lvar1",
                                                            "lvar2",
                                                            "lvar3"])
    print(myDict["lvar1"])

Solution

  • Save the result of locals() (or vars()) call to return the function's local scope. Otherwise, locals() inside the generator expression will return the gen-expr's local scope.

    def test3():
        lvar1 = 1
        lvar2 = 2
        lvar3 = 3
        scope = locals()
        myDict = dict((name, eval(name, scope)) for name in [
                      "lvar1", "lvar2", "lvar3"])
        print(myDict["lvar1"])
    

    BTW, you don't need an explicit comprehension to build that dict:

    # copy() avoids quirky, unexpected updates if something else (like a debugger)
    # accesses locals() or f_locals
    myDict = locals().copy()  # or vars().copy()