Manipulating caller frame

Terry Reedy tjreedy at udel.edu
Tue Dec 17 11:51:41 EST 2002


"Lulu of the Lotus-Eaters" <mertz at gnosis.cx> wrote in message
> Along those lines, the following rather shocks me:
>
>     % cat change_foo.py
>     def change_foo():
>         import inspect
>         caller_locals = inspect.currentframe(1).f_locals
>         caller_locals['foo'] = 'newfoo'
>         return caller_locals
>
>     def somefunc():
>         baz = 'bat'
>         foo = 'bar'
>         print foo
>         l = change_foo()
>         print foo
>         print l, locals()
>         print id(l), id(locals())
>
>     somefunc()
>
>     % python change_foo.py
>     bar
>     bar
>     {'foo': 'newfoo', 'baz': 'bat'} {'l': {...}, 'baz': 'bat',
'foo': 'bar'}
>     584780 584780

Change somefunc to

def somefunc():
        foo = 'bar'
        l = change_foo()
        print l['foo'], locals()['foo'], l['foo']
        print id(l), id(locals())

and the output is

>>> somefunc()
newfoo bar bar
8273776 8273776

> I can accept easily enough (if this is so) that 'caller_locals' is
> really only a copy of the locals() dictionary.

locals() is a dictionary version ('copy') of the local namespace
(implemented for efficiency as an array, for those who don't know) but
caller_locals *is* that same dictionary.

> Which would explain why  changing it doesn't change 'foo'.

It did not change 'foo' in the local namespace but it *did* change it
in the one and only dict copy.

> But what I just can't get my head around is the idea that the 'l'
and
> 'locals()' have the SAME ID, and yet different contents.

Dicts are mutable and have different contents at different times ;).
The locals() function does *not* allocate a new dict but merely
updates a fixed shadow dict to reflect the current state of the local
namespace.

>>> def f():
...   a = locals()
...   b = locals()
...   print id(a), id(b), a is b
...   print a['a']
...
>>>
>>> f()
8265792 8265792 1
{'a': {...}}

The lib ref manual
"locals()
Return a dictionary representing the current local symbol table.
Warning: The contents of this dictionary should not be modified;
changes may not affect the values of local variables used by the
interpreter.
"
warns not to change it, but is not quite explict about the full detail

I submitted SF 'bug' 655271 suggesting that lib ref locals() entry
start with
"Update and return the dictionary..." instead of merely "Return a
dictionary ..", which can be misinterpreted as "Return a *new*
dictionary ...",

> Can someone help me here?

I was puzzled too until I realized that l could not have been deleted
and that l and locals() really must be the same object.


Terry J. Reedy





More information about the Python-list mailing list