From: Gary Herron on
Yingjie Lan wrote:
> --- On Sat, 4/24/10, Steven D'Aprano <steve(a)REMOVE-THIS-cybersource.com.au> wrote:
>
>
>> From: Steven D'Aprano <steve(a)REMOVE-THIS-cybersource.com.au>
>> Subject: Re: NameError: how to get the name?
>> To: python-list(a)python.org
>> Date: Saturday, April 24, 2010, 4:07 PM
>> On Sat, 24 Apr 2010 04:19:43 -0700,
>> 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:
>>
>>
>
> I tried this, and it worked:
>
> Python 2.6.1 (r261:67515, Feb 11 2010, 00:51:29)
> [GCC 4.2.1 (Apple Inc. build 5646)] on darwin
> Type "help", "copyright", "credits" or "license" for more information.
>
>>>> while True:
>>>>
> ... try: print a
> ... except: locals()['a']="HERE YOU ARE"
> ... else: break
> ...
> HERE YOU ARE
>

Yes, but as Steven D'Aprano said, this won't work inside a function.
Try it.

Also if you find an instance where this works, you can't rely on the
behavior. If you RTM, you'll find this:

locals()¶ <http://docs.python.org/library/functions.html#locals>

Update and return a dictionary representing the current local symbol
table. Free variables are returned by locals()
<http://docs.python.org/library/functions.html#locals> when it is
called in function blocks, but not in class blocks.

Note: The contents of this dictionary should not be modified;
changes may not affect the values of local and free variables used
by the interpreter.

Gary Herron




From: Yingjie Lan on
--- On Sat, 4/24/10, Gary Herron <gherron(a)islandtraining.com> wrote:
> From: Gary Herron <gherron(a)islandtraining.com>
> Subject: Re: NameError: how to get the name?
> To:
> Cc: python-list(a)python.org
> Date: Saturday, April 24, 2010, 8:03 PM
> Yingjie Lan wrote:
> > --- On Sat, 4/24/10, Steven D'Aprano <steve(a)REMOVE-THIS-cybersource.com.au>
> wrote:
> >
> >
> >> From: Steven D'Aprano <steve(a)REMOVE-THIS-cybersource.com.au>
> >> Subject: Re: NameError: how to get the name?
> >> To: python-list(a)python.org
> >> Date: Saturday, April 24, 2010, 4:07 PM
> >> On Sat, 24 Apr 2010 04:19:43 -0700,
> >> 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:

============================================
def wrapfun():
while True:
try: print a
except: globals()['a']="HERE YOU ARE"
else: break
finally: print globals()['a']
wrapfun()
============================================

Thanks for the information! BTW, why would
locals() and globals() differ in this respect?
For example:

============================================
def wrapfun():
while True:
try: print a
except: locals()['a']="HERE YOU ARE"
else: break
finally: print locals()['a']
wrapfun()
============================================

That would print "HERE YOU ARE" infinitely.
Apparently, the dict gets modified, but is
not the same as the one actually used to
resolve name 'a' in the statement 'print a'.

Yingjie



From: Chris Rebert on
On Sat, Apr 24, 2010 at 4:17 PM, Yingjie Lan <lanyjie(a)yahoo.com> wrote:
> --- On Sat, 4/24/10, Gary Herron <gherron(a)islandtraining.com> wrote:
>> From: Gary Herron <gherron(a)islandtraining.com>
>> Date: Saturday, April 24, 2010, 8:03 PM
>> Yingjie Lan wrote:
>> > --- On Sat, 4/24/10, Steven D'Aprano <steve(a)REMOVE-THIS-cybersource.com.au>
>> wrote:
>> >> From: Steven D'Aprano <steve(a)REMOVE-THIS-cybersource.com.au>
>> >> Subject: Re: NameError: how to get the name?
>> >> To: python-list(a)python.org
>> >> Date: Saturday, April 24, 2010, 4:07 PM
>> >> On Sat, 24 Apr 2010 04:19:43 -0700,
>> >> 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).

Cheers,
Chris
--
http://blog.rebertia.com
From: Yingjie Lan on
--- On Sun, 4/25/10, Chris Rebert <clp2(a)rebertia.com> wrote:

> From: Chris Rebert <clp2(a)rebertia.com>
> Subject: Re: NameError: how to get the name?
> To: "Yingjie Lan" <lanyjie(a)yahoo.com>
> Cc: python-list(a)python.org
> Date: Sunday, April 25, 2010, 3:27 AM
> On Sat, Apr 24, 2010 at 4:17 PM,
> Yingjie Lan <lanyjie(a)yahoo.com>
> wrote:
> > --- On Sat, 4/24/10, Gary Herron <gherron(a)islandtraining.com>
> wrote:
> >> From: Gary Herron <gherron(a)islandtraining.com>
> >> Date: Saturday, April 24, 2010, 8:03 PM
> >> Yingjie Lan wrote:
> >> > --- On Sat, 4/24/10, Steven D'Aprano <steve(a)REMOVE-THIS-cybersource.com.au>
> >> wrote:
> >> >> From: Steven D'Aprano <steve(a)REMOVE-THIS-cybersource.com.au>
> >> >> Subject: Re: NameError: how to get the
> name?
> >> >> To: python-list(a)python.org
> >> >> Date: Saturday, April 24, 2010, 4:07 PM
> >> >> On Sat, 24 Apr 2010 04:19:43 -0700,
> >> >> 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?

Yingjie



From: Chris Rebert on
On Sat, Apr 24, 2010, Yingjie Lan <lanyjie(a)yahoo.com> wrote:
> On Sun, 4/25/10, Chris Rebert <clp2(a)rebertia.com> wrote:
>> On Sat, Apr 24, 2010, Yingjie Lan <lanyjie(a)yahoo.com> wrote:
>> > On Sat, 4/24/10, Gary Herron <gherron(a)islandtraining.com> wrote:
>> >> Yingjie Lan wrote:
>> >> > On Sat, 4/24/10, Steven D'Aprano <steve@--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