Dynamic and Static scoping in Lisp vs. Python [was: Scoped change of a global variable]

Steven Majewski sdm7g at Virginia.EDU
Wed Jan 2 20:58:54 EST 2002


On Wed, 2 Jan 2002, Steven Majewski, talking to himself again,  wrote:

>
> An interesting problem: that sort of construct, both in builtin's like
> 'with-open-file' and custom ones using 'let' is one of the most commonly
> used (and useful) applications of nested scope in Lisp
>
> Now that Python 2.2 has nested scopes, I would have thought there was a
> simple way to do it, but if there is, it eludes me.

I was confusing myself about what happens in Lisp vs. Python.

In Lisp, there are 'special variables' which are dynamically bound,
and are declared special and usually follow the name convention of:
*something* . Basically, all module globals in Python are 'special'.
(This is one of the ways in which Python is usually more dynamic
than Lisp -- this was asked in another thread.)

But in Lisp, I can rebind even those special variables using nested
scopes:

 	(let (( *readtable*   (make-new-readtable .. )))
		( read ...

The first time I tried to do something like that in Lisp I used
UNWIND-PROTECT (the Lisp equiv. of try/finally) in a similar way
to Alex's example, to change the readtable and reset it when I
was done. Then I discovered that the idiom above was the easier
way to do it.

Both Python and Lisp support both static scoping and dynamic
variables, but the difference is that Python doesn't have any
sort of block structure other than function definition in which
to create new bindings.

If there was a Python equivalent of Lisp's LET block, then the
python code would be something like:

globalModuleVar = 1

## define functions which access globalModuleVar
## value in function will be whatever globalModuleVar is bound to
## at the time of execution.

block:
	globalModuleVar = 100
	# call functions in env. where globalModuleVar = 100

## outside of that block, the old binding is active.

Which is just a syntactically sugured version of Alex's
	try: save old globals, assign new values, do something...
	finally: restore old globals


Except that in Python, global references in a function are to
the module in which the function is defined. There's no top-level
scope as in Lisp. In Python, __main__ is just another module.


Lisp code typically contains  a lot more static scoping blocks,
and so it tends to restrict the symbols that need to be dynamically
looked up (compared to Python).


> The one simple way of doing it doesn't use nested scopes at all,
> but uses new.function to construct a function with a new global
> dict:


A more general purpose version would need to keep all of the other
bindings from the global namespace -- the example I used didn't
call any other functions (which would have given a NameError),
but used the print statement, witch is part of the language, not
a name lookup.

Something like:

>>> def rebind( func, **newbindings ):
...	"return a new function with bindings to new global symbols"
...     newdict = copy.copy( func.func_globals )
...     newdict.update( newbindings )
...     return new.function( func.func_code, newdict )
...


-- Steve Majewski






More information about the Python-list mailing list