--- On Sun, 4/25/10, Chris Rebert <c...@rebertia.com> wrote: > From: Chris Rebert <c...@rebertia.com> > Subject: Re: NameError: how to get the name? > To: "Yingjie Lan" <lany...@yahoo.com> > Cc: "python list" <python-list@python.org> > Date: Sunday, April 25, 2010, 10:09 AM > On Sat, Apr 24, 2010, Yingjie Lan > <lany...@yahoo.com> > wrote: > > On Sun, 4/25/10, Chris Rebert <c...@rebertia.com> > wrote: > >> On Sat, Apr 24, 2010, Yingjie Lan <lany...@yahoo.com> > wrote: > >> > On Sat, 4/24/10, Gary Herron <gher...@islandtraining.com> > wrote: > >> >> Yingjie Lan wrote: > >> >> > On Sat, 4/24/10, Steven D'Aprano > <st...@--cybersource.com.au> > wrote: > >> >> >> On Sat, 24 Apr 2010, Yingjie Lan > wrote: > >> >> >>> I wanted to do something > like this: > >> >> >>> > >> >> >>> while True: > >> >> >>> try: > >> >> >>> def fun(a, b=b, c=c): > >> >> pass > >> >> >>> except NameError as ne: > >> >> >>> name = > >> >> get_the_var_name(ne) > >> >> >>> locals()[name] = '' > >> >> >>> else: break > >> >> >>> > >> >> >> This won't work. Writing to > locals() does > >> not > >> >> actually > >> >> >> change the local variables. Try > it inside > >> a > >> >> function, and you will see it > >> >> >> doesn't work: > >> > > >> > No it DOESN'T work, and both of you are > precisely > >> correct. > >> > Just for playing around, I substituted > >> > "locals()" by "globals()" and it worked as > desired: > >> <snip> > >> > Thanks for the information! BTW, why would > >> > locals() and globals() differ in this > respect? > >> > >> The module-level (i.e. global) namespace is > implemented by > >> CPython > >> using an actual dictionary; globals() returns a > proxy to > >> that > >> dictionary and lets you manipulate it. > >> In contrast, as an optimization, CPython > implements local > >> variables in > >> functions using predetermined offsets into an > array of > >> predetermined > >> length; the dictionary returned by locals() is > dynamically > >> constructed > >> on-demand and does not affect the actual array > used for the > >> local > >> variables (I suppose it could have been made to do > so, but > >> there's > >> probably a complexity or optimization reason for > why not). > >> > > > > Thanks, that's good to know. The locals() behaves > rather > > strangely, as can be demonstrated by the following > two > > tests (the first one is from Steven, thanks Steve): > > > > #file: fun.py: > > > > def test(): > > x = 1 > > print (x) > > locals()['x'] = 2 > > print (x, locals()['x']) > > > > def test2(): > > locals()['x'] = 2 > > print (locals()['x']) > > print x > > > > test() > > test2() > > > > -----And the output: python fun.py------- > > 1 > > (1, 1) > > 2 > > Traceback (most recent call last): > > File "fun.py", line 21, in <module> > > test2() > > File "fun.py", line 17, in test2 > > print x > > NameError: global name 'x' is not defined > > > > ------------- > > > > I don't know how to make sense out of it. > > Any suggestions? > > My working theory is that attempting to modify a key in > locals() > corresponding to an extant variable has no effect, even on > just the > locals() dictionary itself, and is ignored, but adding or > modifying > other keys in locals() works like a normal dictionary. > > def test3(): > x = 1 > print x > locals()['x'] = 2 > locals()['y'] = 3 > print x, locals()['x'], locals()['y'] > print y > > $ python test3.py > 1 > 1 1 3 > Traceback (most recent call last): > File "Desktop/tmp.py", line 22, in <module> > test3() > File "Desktop/tmp.py", line 7, in test3 > print y > NameError: global name 'y' is not defined > > > As for why you get a NameError in test2() [assuming that's > part of > what's confusing you], there's no assignment to `x` in > test2(), so > Python reasons you must be referring to a global variable > `x`. But > there is no such global variable, hence the NameError. > > Cheers, > Chris > --
Thanks, very nice observations. What's puzzling me is this: in the first test, it seems locals() ignores assignment, thus locals()['x'] == x holds True, but in the second one, as 'x' does not exists, it allows assignment. I might assume this: locals() keeps two mappings: one is the true locals, another is an ordinary dict (let's called the faked one). when you look up a value, it first looks into the true locals, then the faked one only if not found there. As for setting a value, it always works on the faked one. That's my best guess, anyway. It seems better to be explicit: simply throws an exception whenever one tries to set a value for locals()['x'] -- just say that locals() are unlike globals(), it is read only. Yingjie -- http://mail.python.org/mailman/listinfo/python-list