NameError: how to get the name?

Chris Rebert clp2 at rebertia.com
Sun Apr 25 02:09:12 EDT 2010


On Sat, Apr 24, 2010, Yingjie Lan <lanyjie at yahoo.com> wrote:
> On Sun, 4/25/10, Chris Rebert <clp2 at rebertia.com> wrote:
>> On Sat, Apr 24, 2010, Yingjie Lan <lanyjie at yahoo.com> wrote:
>> > On Sat, 4/24/10, Gary Herron <gherron at islandtraining.com> wrote:
>> >> Yingjie Lan wrote:
>> >> > On Sat, 4/24/10, Steven D'Aprano <steve at --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
--
Your mail client's quoting style is a bit annoying.
http://blog.rebertia.com



More information about the Python-list mailing list