3

I am new to programming and skim read some topics on functions and classes. So after reading about fucntions and enclosing functions, I tried to mimic inheritance search in classes by only minipulating functions and its scope.

Example:

For the Code

def f1():
    t=1
    def f2(x):
        return eval(x)
    return f2

Why do I get a name error when doing

f1()('t') #expecting 1 return

But not when defining say

def f1():
    t=1
    def f2():
         return t
    return f2

f()() # 1 is returned here

I could solve this problem by defining t as nonlocal in the scope of f2, which mean that the first code only looks in the local scope of f2. Why does this happen? `

HEADLESS_0NE
  • 3,416
  • 4
  • 32
  • 51
deftextra
  • 123
  • 1
  • 7
  • 2
    Please indent your code – ForceBru Jun 09 '17 at 16:54
  • [Related.](https://stackoverflow.com/questions/44425363/is-it-true-in-python-closure-will-be-stored-if-and-only-if-it-is-mentioned-lex) – Aran-Fey Jun 09 '17 at 17:02
  • Look at the accepted answer of https://stackoverflow.com/questions/4020419/why-arent-python-nested-functions-called-closures - very nice explanation there. – mkiever Jun 09 '17 at 17:18

1 Answers1

1

The issue here is the context for eval. By default, eval uses the locals and globals from the environment in which it is called. If we write:

def f1():
    t = 1

    def f2(x):
        return eval(x)
    return f2

then inside f2, t is not included in either the globals or locals and will therefore be inaccessible to the eval statement. Python will only add t to the locals for f2 if t is actually used within f2. Thus, somewhat surprisingly, the following code will execute correctly:

def f1():
    t = 1

    def f2(x):
        print(t)
        return eval(x)
    return f2

since t is now used within f2. A better way of ensuring this always works is to do the following:

def f1():
    t = 1
    eval_globals = globals()
    eval_locals = locals()

    def f2(x):
        return eval(x, eval_globals, eval_locals)
    return f2

This overrides the context for eval, providing the globals and locals from within the scope of f1.

A caveat, since you mention that you're a new programmer: In general, you should avoid eval statements period unless you have a good reason for using them. There are better ways to achieve what you're doing here without resorting to an eval.

wphicks
  • 355
  • 2
  • 9