NameError in function, nested in __init__ method

Question:

class sheet:
    def __init__(self):
        def close_game():
            print("game closed")
        def click():
            eval("close_game()")

        click()

s1 = sheet()

I’m getting such error:

  File "<string>", line 6, in click
NameError: name 'close_game' is not defined

But if I replace ‘eval("close_game()")’ with ‘close_game()’ it works correctly. Please explain to me why it works like that.

Asked By: Lesolas

||

Answers:

The reason is that eval sets up its own namespace and close_game is not present in that namespace by default. You can add it explicitly like this:

...
        def close_game():
            print("game closed")
        def click():
            eval("close_game()", {"close_game": close_game})

Then it will resolve properly and the function will be called as expected.

PS: I suppose it is prudent to mention that using eval is usually risky business. Just in case you are not aware, it is easy to introduce huge security vulnerabilities. This has been discussed on this platform extensively, so I am just going to leave this warning.

Answered By: Daniil Fajnberg

eval does not have access to the scope chain. It can only see immediate local variables by default:

def outer():
    non_loc = 1

    def inner_var():
        print(non_loc)

    def inner_eval():
        print(eval('non_loc'))

    inner_var()   # ok
    inner_eval()  # not ok


outer()

You can, however, pass whatever you want in the locals argument.

Answered By: gog
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.