binding a reference to a variable

Alex Martelli aleax at aleax.it
Wed Apr 10 06:53:14 EDT 2002


<posted & mailed>

Andrew Koenig wrote:

>>> Now, f is an object that I can use to rebind the name x.  For
>>> example, if I execute f(42), that sets x to 42.
> 
> Aahz> You really don't want to do this in Python.
> 
> One thing that fascinates me is how the nature of a language affects
> the preferred idioms therein.  To help me further my understanding,
> would you mind explaining to me why this particular idea is undesirable

Guess you could describe it as a social contract about "who/what binds
a function's local variables".  The Python answer is, only the code of
the function itself binds the function's local variables -- the very
fact of binding a name ("unqualified" name, if you will -- dots apart!) in 
a function is what defines that name as being local (unless a global
statement explicitly says otherwise).  Local variables are bound by
assignment statements (plain ones, with just '='; augmented ones may
sometimes RE-bind, but never give a name its first binding... pity
that using an augmented assignment ONLY, *still* tags the variable as
local, but I guess either choice would have problems) or one of a few
other statements that bind names (def, class, import, from).  Binding
with an exec statement is possible but "considered harmful" -- exec
is too powerful and hard to control, particularly if you don't use
it with explicit dictionaries, and thus tends to produce subtle, hard
to find bugs too often.  There are almost always better alternatives.

Part of the social contract comes from higher level issues, but part
of it stems from a long-standing optimization: locals() is NOT a
real rebindable dictionary, but just masquerades as one in some
ways; KNOWING that local variables are only bound by the code of
the function itself lets the compiler perform a crucial optimization.

What you could see as a further social contract is: any call such
as f(x) NEVER has any effect on the BINDING of name x -- possibly
on the OBJECT to which name x is bound, if that object is mutable,
but not on the binding itself.  Knowing that constraint allows a
lot of reasoning about what's going on, that would be harder or
impossible if that constraint wasn't there.  Here, there are really
no implementation issues in play -- this holds for global names
(which _are_ generally rebindable from just about everywhere) and
"composite" names too (such as x.y) -- it IS a social contract that
puts such "rebindings as a side effect of function calls on
names used as arguments" out of bounds.  Function f receives no
information at all about what names or other syntax forms were
used to obtain the actual-arguments it receives -- it just gets
the values of the actual-arguments.  So for example after:
    x = y = whatever_expression_you_want
    f(x)
there is NO way for f to ascertain whether it was called as
f(x) or rather as f(y) -- short, I guess, of rooting through the
call stack and looking for source files or bytecode of its
caller to find out.  Thus, it's socially "unthinkable" that
there would be any specific effect on the exact name used by
f's caller... given that f cannot even find out about that
name (not portably, not with a bounded amount of effort).


Given all this, if you find out and implement some Ruby Goldberg scheme 
that works (sort of) this way, you'll have code that is totally baffling to 
Pythonista users thereof, because it runs so deeply counter to our
expectations, our usual social contracts.


Alex




More information about the Python-list mailing list