Weird lambda rebinding/reassignment without me doing it

Terry Reedy tjreedy at udel.edu
Thu Jul 10 20:09:16 CEST 2008



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'.  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.

> 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.

>> 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




More information about the Python-list mailing list