Statement local namespaces summary (was Re: python3: 'where' keyword)

Nick Coghlan ncoghlan at iinet.net.au
Fri Jan 14 07:05:08 EST 2005


Nick Coghlan wrote:
> as equivalent to:
> 
> def __use_stmt():
>   <use-suite>
>   def _in_clause():
>     <in-suite>
>     return <names>
>   return _in_clause()
> __use_stmt_args = {}
> <names> = __use_stmt()
> del __use_stmt
> 

The more I think about this return-based approach, the less I like it. It could 
probably be made to work, but it just feels like a kludge to work around the 
fact that the only mechanisms available for altering the bindings of local names 
are assignment and definition statements.

For class namespaces, getattr(), setattr() and delattr() work a treat, and 
globals() works fine for module level name binding.

locals() is an unfortunate second class citizen, since it writes to it aren't 
propagated back to the executing frame. Programmatic interrogation of locals is 
fine, but update is impossible.

What would be interesting is if locals() returned a dictionary whose __setitem__ 
method invoked PyFrame_LocalsToFast on the relevant frame, instead of a vanilla 
dictionary as it does now.

Then locals()["x"] = foo would actually work properly.

Notice that you can get this effect today, by using exec to force invocation of 
PyFrame_LocalsToFast:

Py> def f():
...   n = 1
...   def g(outer=locals()):
...    outer["n"] += 1
...   g() # Does not affect n
...   print n
...   exec "g()" # DOES affect n
...   print n
...
Py> f()
1
2

(The call to g() has to be inside the exec statement, since the exec statement 
evaluation starts with a call to PyFrame_FastToLocals).

Assuming a writeable locals(), the semantics for the normal case are given by:
============
def __use_stmt(__outer):
   <use-suite>
   <in-suite>
   __inner = locals()
   for name in <names>:
     __outer[name] = __inner[name]

__use_stmt(locals())
del __use_stmt
============

And for the 'delayed execution' case:
============
def __named_use_stmt(__outer):
   <use-suite>
   def __delayed_block():
     <in-suite>
     __inner = locals()
     for name in <names>:
       __outer[name] = __inner[name]

   return __delayed_block

<in-name> = __named_use_stmt(locals())
del __named_use_stmt
============

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at email.com   |   Brisbane, Australia
---------------------------------------------------------------
             http://boredomandlaziness.skystorm.net



More information about the Python-list mailing list