On Wed, 8 Feb 2023 at 10:18, Mark Bourne <nntp.mbou...@spamgourmet.com> wrote: > > Stefan Ram wrote: > > Mark Bourne <nntp.mbou...@spamgourmet.com> writes: > >> In the second case, eval() only gets the globals and immediate locals, > > > > Yes, I think you are right. Curiously, the following program would > > mislead one to thing that eval /does/ see the intermediate names: > > > > main.py > > > > def f(): > > x = 22 > > def g(): > > print( x ) > > print( eval( 'x' )) > > g() > > f() > > > > output > > > > 22 > > 22 > > > > . But "print( x )" had the effect of making that x local. > > Without it, we see the error: > > > > main.py > > > > def f(): > > x = 22 > > def g(): > > print( eval( 'x' )) > > g() > > f() > > > > error output > > > > NameError: name 'x' is not defined
Don't know if Stefan realises it, but newsgroup text that gets replies ends up on the mailing list. So if this is a problem of copyright, you should probably stop posting to the newsgroup - unless you want people like Mark to unintentionally violate your copyright. > That is interesting. I know assigning to a value creates a local > version (and the non-local then can't be accessed, even before the new > value was assigned), but hadn't realised just referencing it brought it > into local scope for reading. I guess that's to do with closures, where > any variables referenced within the function get bound to the function's > scope. e.g. if g() includes a reference to x [as it does in the first > example above], and f() returned a reference to g(), calling g() later > [from outside of f()] by using that reference would still be able to > access x. Yep, that's to do with closures. Your analysis is spot on. When a name is local to an outer function and referenced in an inner function, it becomes a nonlocal in both functions. You can also declare it with "nonlocal x" in the inner function, which - like with a global statement - allows you to assign to it. > With just the eval() call and no other reference to x, the interpreter > doesn't know at that time the closure is created that there is a > reference to x. At that point, the 'x' is just text in a string. It's > only when eval() gets called that it tries to execute that string as > Python code - and finds that x isn't in scope. Mostly true, yes. The eval function doesn't get any magic ability to refer to nearby variables, so what it does is it depends on the globals() and locals() mappings (which can be the same dictionary under some circumstances). I think you'll agree that globals() does not and should not contain a reference to x here. It's definitely not a global. But is x a local? Well, technically it's a nonlocal; but more importantly, there's a difference between "theoretically could be a nonlocal" and "is actually a nonlocal", as demonstrated by this: def f(): x = 42 def g(): print("without", locals()) g() def h(): x print("with", locals()) h() So, can eval() find x? x = 1234 def f(): x = 42 def g(): print("without", eval("x")) g() def h(): x print("with", eval("x")) h() >>> f() without 1234 with 42 The compiler knows exactly which names are *theoretically available* (which is a lexical concept), but at run time, the only names that are actually available are those which have been captured. ChrisA -- https://mail.python.org/mailman/listinfo/python-list