[Tutor] Question about lambda and new.instancemethod

Kent Johnson kent37 at tds.net
Tue Jul 17 13:17:32 CEST 2007


Tino Dai wrote:
> Hi Everybody,
> 
>      I have been working on a parser for myself. I want to create 
> methods on the fly with the information that I get from a file. Here is 
> my question:
> 
> class configure:
>          <.....stuff deleted......>
>          def parseGlobal(self,projectName,section,project):
>                for element in section.childNodes:
>                      if not element.nodeName == "#text":
>                      self.glblFunc ["get" + 
> project.getAttribute("name").encode("ascii").capitalize()  + 
> element.nodeName.encode("ascii").capitalize()] = \
>                      lambda self : element.firstChild.data.encode ("ascii")
> 
>           <...and later on...>
> 
> def addMethod(instName,funcDict):
>     for k,v in funcDict.iteritems():
>         instName.__dict__[k]=new.instancemethod(v,instName,'configure')
> 
> The instance name and funcDict (which is the populated self.glblFunc) 
> get sent up to addMethod. This is supposed to create a new method within 
> the instance of my class. Instead, I get a AttributeError exception 
> thrown. 

What is the AttributeError and when do you get it?

I see a couple of possible problems.

First, closures don't work the way you want them to in your lambda. Each 
lambda will be bound to the same value of element - the last value of 
element. Here is a simple example showing the problem:

In [1]: funcs = []
In [2]: for i in range(3): funcs.append(lambda: i)
In [3]: for f in funcs:
    ...:     print f()
2
2
2

A simple workaround is to bind the changing variable as a default 
argument to the lambda:

In [4]: funcs = []
In [5]: for i in range(3): funcs.append(lambda i=i: i)
In [6]: for f in funcs:
     print f()
0
1
2

Another fix is to create a factory function that returns the lambda as 
its result.

Second problem is that the third argument to new.instancemethod() should 
be the class object, not the name of the class.

You might find this helpful:
http://groups.google.com/group/comp.lang.python/browse_thread/thread/cc04b8e480d4be62/

> So, I check the code using inspect.getsource, and for all of the 
> new methods that I create, I get
> 
> 
> '                + element.nodeName.encode("ascii").capitalize()] = 
> lambda self :  sys.stdout.write(element.firstChild.data.encode 
> ("ascii"))\n\n'
> 
> instead of
> 
> lambda self :  sys.stdout.write(element.firstChild.data.encode("ascii")

Seems like getsource() is just a little confused, but it is showing you 
the correct source. If you created the lambda on a line by itself it 
might give a better result.

Kent


More information about the Tutor mailing list