Weird lambda rebinding/reassignment without me doing it

David C. Ullrich dullrich at sprynet.com
Fri Jul 11 18:15:19 CEST 2008


In article <mailman.276.1215713371.20628.python-list at python.org>,
 Terry Reedy <tjreedy at udel.edu> wrote:

> David C. Ullrich wrote:
> > In article 
> > <02ff4326-7b07-4ae6-8607-f58ea61802ef at z72g2000hsb.googlegroups.com>,
> >  ssecorp <circularfunc at gmail.com> wrote:
> > 
> >> I am never redefining the or reassigning the list when using validate
> >> but since it spits the modified list back out that somehow means that
> >> the modified list is part of the environment and not the old one.
> >> i thought what happend inside a function stays inside a function
> >> meaning what comes out is independent of what comes in.
> >> Meaning if I want the list I send as a parameter to the function I
> >> have to do x = func(x) and not just func(x) and x is magically what
> >> comes out of func().
> > 
> > A function cannot modify the value of a global variable
> 
> Yes it can.
>  >>> a=[]
>  >>> def f():
> 	a.append('yes I can')
> 
>  >>> f()
>  >>> a
> ['yes I can']
> 
> > (unless it specifies "global"). It doesn't reassign anything.
> 
> The statement 'global a' would allow f to *rebind* the global *name* 
> 'a'. 

Aargh. That's exactly what I meant, sorry. 

> The word 'variable' should almost not be used in discussing Python 
> since it is often unclear whether it refers to a name (or collection 
> slot) or an object bound thereto.

Indeed. Which is exactly why I included those snippets of
code that you snipped, one of which does exactly what your
snippet above does... you're probably right, "variable" is
a bad idea, and "modify the value of a variable" is a very
bad idea.

The code doesn't "modify the value of the variable" in the
sense that the value of the variable is a certain object,
and after the function call the value is the same object.
It does "modify the value of the variable" in the sense
that the object which is the value of the variable has been
modified.

There's a problem here. Please note that this is not a criticism,
and I don't really know what anyone could do about the problem.
The problem is that if the reader is not accustomed to thinking
explicitly about what's going on under the hood when code is
executed he's going to have a hard time understanding the
difference between "assigning a value to a variable" and
"binding a name to an object". Once I realized that dicts
rule everything this became clear to me, but for some time
the discussions I saw on all this made no sense to me.

Which is why I think it's a good idea to include examples
illustrating what can and cannot be done, which is why I
did that. I tend to suspect that the OP is at least as 
confused on the subtlties as I was back then (evidence below).

> > But in the functions below you're not reassigning a variable,
> > you're _modifiying_ an object. A function _can_ modify an
> > object you pass to it:
> 
> It can modify any mutable object it can access.
> 
> >> Doesnt Python have closure or that isnt what this is about?
> 
> Python does have closures.  This is not about that.

This is why I suspect what I say I suspect. He's thought
that the word "closure" meant something like "local scope"...

> >> def validate(placed):
> >>     student = round(random.random()*401)
> >>     if student in placed:
> >>         return validate(placed)
> >>     else:
> >>         placed.append(student)
> >>         return student, placed
> 
> Delete this. It is redundant with the below.
> 
> >> def val(placed):
> >>     student = round(random.random()*401)
> >>     if student in placed:
> >>         return validate(placed)
> >>     else:
> >>         placed.append(student)
> >>         return student
> 
> I believe this is equivalent to
> 
> def addval(placed):
>    while True:
>      student = round(random.random()*401)
>      if student not in placed:
>        break
>    placed.append(student)
>    return student
> 
> While this avoids the indefinite recursion depth problem, it does not 
> avoid the indefinite time problem.  Use random.shuffle, or write your 
> own version if doing this for practice.  Also consider removing the 
> return statement unless you actually directly use the added value.  It 
> is easier to remember that addval mutates 'placed' without the return.
> 
> >>>>> g = lambda x:validate(x)
> 
> This is doubly diseased.
> 
> First, never write a 'name = lambda...' statement since it is equivalent 
> to a def statement except that the resulting function object lacks a 
> proper .funcname attribute.  The above only trivially abbreviates
>    def g(x): return validate(x)
> by 3 characters.  Another reason is that the lambda form somehow more 
> often tricks people into the next mistake .
> 
> Second, never write a function (with either def or lambda) that simply 
> returns a function of the argument(s).  The wrapping does nothing!  This 
> is a waste of time and space for both you and the interpreter.  The 
> above is functionally equivalent to
>    g = validate
> and if you want that, you could name the function 'g' when you define it.
> 
> >>>>> l=[]
> In some fonts, 'l' and '1' are nearly identical; please use something 
> else for public code, which you made this to be by posting it;-)
> 
> >>>>> for x in range(1,10):
> >> 	g(l)
> As said, the 'g' wrapper is useless.
>         addval(l)
> 
> Hope this helps.
> 
> Terry Jan Reedy

-- 
David C. Ullrich



More information about the Python-list mailing list