Python becoming less Lisp-like

Bengt Richter bokr at oz.net
Fri Mar 18 14:58:17 EST 2005


On Fri, 18 Mar 2005 09:16:42 -0800, Jeff Shannon <jeffshannon at gmail.com> wrote:

>Antoon Pardon wrote:
>> Op 2005-03-16, Jeff Shannon schreef <jeffshannon at gmail.com>:
>> 
>>>Bruno Desthuilliers wrote:
>>>
>>>>- if x is a class attribute of class A and a is an instance of A, 
>>>>a.x=anyvalue create a new instance attribute x instead of modifying A.x
>>>
>>>This is very consistent with the way that binding a name in any scope 
>>>will shadow any bindings of that name in "higher" scopes.  It is the 
>>>same principle by which one is able to use the same name for a 
>>>function-local variable that is used for a global variable, without 
>>>destroying that global variable.  [...]
>> 
>> Not entirely. The equivallent is imposible in function scope.
>> If function scope would work exactly equivallent as the
>> above the following should work 
>> 
>>     a = 42
>>     def f():
>>       a = a + 1
>>       print a
       f()   # ;-)
>>     print a
>> 
>> And the result should be:
>> 
>> 43
>> 42
>>
IIRC, in some past version that used to be the way it worked (if you don't forget to call f() ;-)
I think it is logical. I.e., the right hand side of a = a + 1
is logically evaluated first, so the status at that time should IMO
determine the meaning of "a" -- i.e., look for it in an outer scope.
Next comes the local assignment of "a" which should create a local name
binding, but the code for determining the assigned value should IMO
be the code for the "a + 1" with no local binding of "a" yet existing.

I don't know how much code would break to go back to that, but maybe
not so much, since it's not legal now:

 >>> a = 42
 >>> def f():
 ...     a = a +1
 ...     print a
 ...
 >>> f()
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
   File "<stdin>", line 2, in f
 UnboundLocalError: local variable 'a' referenced before assignment
 >>> print a
 42

BTW, I would like a re-assign or find-and-rebind operation spelled ":=" which would
make x := 123 mean look for x as if to read its value in a right hand side expression,
(except do not look into __builtins__) and wherever found, rebind to 123 -- and if not found,
raise an exception.

I think var := 'something' would be a useful substitute for the idiom of
var[0] = 'something' and be unambiguous.

":=" as an operator could combine like <op>= if desired, so we could write
    var +:= some.long.expression[that].you('do')**not.want.to.type.twice
instead of
    _ = some.long.expression[that].you('do')**not.want.to.type.twice
    var +:= _  # meaning var := var + _
or such.

>
>I'd still say that the name binding rules are very consistent.  The 
They are consistent, but I have to say the function-body full lookahead to determine
local vs outer (not to mention normal function vs generator) jars my sensibilities.

>name lookup rules are a little different (as they *should* be for 
>class/instance attributes), and that's why there's a different net 
>effect (UnboundLocalError) as shown in your example.  I'd say, 
>however, that if there's a special case here it's with the 
>function-local variables, not the class/instance attributes.  It's the 
>optimizations to the function-local namespace which prevent 
>transparent re-binding of global names.  And given that the 
>function-local namespace is by far the most heavily used, and the 
>relative utility (and wisdom) of using globals in this way, this is a 
>case where the benefit of the special case is well worth the cost of 
>its slight inconsistency.
The optimization argument goes away with x := something I think, since
the x search can be limited to looking in the lexical environment
exactly like looking for read-only outer scope names now, just with
different consequences for finding or not finding.

Regards,
Bengt Richter



More information about the Python-list mailing list