puzzled by name binding in local function

Ulrich Eckhardt ulrich.eckhardt at dominolaser.com
Wed Feb 6 11:19:59 CET 2013


Dave and Terry,

Thanks you both for your explanations! I really appreciate the time you 
took.

Am 05.02.2013 19:07, schrieb Dave Angel:
> If you need to have separate function objects that already know a
> value for i, you need to somehow bind the value into the function object.
>
> One way to do it, as you say, is with default parameters.  A function's
> default parameters are each stored in the object, because they're
> defined to be evaluated only once.  That's sometimes considered a flaw,
> such as when they're volatile, and subsequent calls to the function use
> the same value.  But in your case, it's a feature, as it provides a
> standard place to store values as known at function definition time.

Yes, that was also the first way I found myself. The reason I consider 
this non-obvious is that it creates a function with two parameters (one 
with a default) while I only want one with a single parameter. This is 
to some extent a bioware problem and/or a matter of taste, both for me 
and for the other audience that I'm writing the code for.


> The other way to do it is with functions.partial().  I can't readily
> write you sample code, as I haven't messed with it in the case of class
> methods, but partial is generally a way to bind one or more values into
> the actual object.  I also think it's clearer than the default parameter
> approach.

Partial would be clearer, since it explicitly binds the parameters:

import functools

class Foo(object):
     def function(self, param):
         print('function({}, {})'.format(self, param))
Foo.test = functools.partial(Foo.function, param=1)

f = Foo()
Foo.test(f) # works
f.test() # fails

I guess that Python sees "Foo.test" and since it is not a (nonstatic) 
function, it doesn't create a bound method from this. Quoting the very 
last sentence in the documentation: "Also, partial objects defined in 
classes behave like static methods and do not transform into bound 
methods during instance attribute look-up."

The plain-Python version mentioned in the functools documentation does 
the job though, so I'll just use that with a fat comment. Also, after 
some digging, I found http://bugs.python.org/issue4331, which describes 
this issue. There is a comment from Jack Diederich from 2010-02-23 where 
he says that using lambda or a function achieves the same, but I think 
that this case shows that this is not the case.

I'm also thinking about throwing another aspect in there: Unless you're 
using exec(), there is no way to put any variables as constants into the 
function, i.e. to enforce early binding instead of the default late 
binding. Using default parameters or functools.partial are both just 
workarounds with limited applicability. Also, binding the parameters now 
instead of later would reduce size and offer a speedup, so it could be a 
worthwhile optimization.


> The main place where I see this type of problem is in a gui, where
> you're defining a callback to be used by a series of widgets, but you
> have a value that IS different for each item in the series.  You write a
> loop much like you did, and discover that the last loop value is the
> only one used. The two cures above work, and you can also use lambda
> creatively.

Careful, lambda does not work, at least not easily! The problem is that 
lambda only creates a local, anonymous function, but any names used 
inside this function will only be evaluated when the function is called, 
so I'm back at step 1, just with even less obvious code.


Greetings!

Uli





More information about the Python-list mailing list