lambdas

Thomas Jollans thomas at jollans.com
Mon Jun 14 18:38:29 EDT 2010


On 06/15/2010 12:06 AM, Craig Yoshioka wrote:
> I'm trying to write a class factory to create new classes dynamically at runtime from simple 'definition' files that happen to be written in python as well.  I'm using a class factory since I couldn't find a way to use properties with dynamically generated instances, for example:
> 
> I would prefer this, but it doesn't work:
> 
> class Status(object):
> 	pass
> 
> def makeStatus(object):
> 	def __init__(self,definitions):
> 		for key,function in definitions:
> 			setattr(self,key,property(function))
> 
> this works (and it's fine by me):
> 
> def makeStatus(definitions):
> 	class Status(object):
> 		pass
> 	for key,function in definitions:
> 		setattr(Status,key,property(function))
> 	return Status()
> 
> but I would also like the functions to only be evaluated when necessary since some may be costly, so I want to do the following:
> 
> def makeStatus(definitions):
> 	class Status(object):
> 		pass
> 	for key,function,data in definitions:
> 		setattr(Status,key,property(lambda x: function(data)))
> 	return Status()
> 
> but all my properties now act as if they were invoked with the same data even though each one should have been a new lambda function with it's own associated data.  It seems Python is 'optimizing'?  all the lambdas to the same object even though that's clearly not what I want to do.  Anyone have any suggestions as to:
> 
> 1) why

(I'm not 100% sure about this)
I think that when Python encounters "function(data)" while executing any
one of the lambdas, looks in the scope of the factory function, and uses
the last value data had there - which has since changed. This old trick
might help: (if it doesn't, my analysis was wrong)

> 2) what I should do

setattr(Status, key, property(lambda x, d=data: function(d)))


> 3) a better way in which to implement this pattern

how about this:

class Status(object):
    def __init__(self, definitions):
        """definitions must be a { key: function, ... } mapping"""
        self.functions = definitions
        self.cache = {}

    def __getattribute__(self, name):
        if name in self.cache:
            return self.cache[name]
        elif name in self.functions:
            self.cache[name] = self.functions[name]()
            return self.cache[name]
        else:
            return super(Status, self).__getattribute__(name)

This doesn't use properties (why should it?) and proposes a different
format for the definitions: a dict instead of a sequence of tuples.
dict([(a,b), (c,d)]) == {a: b, c: d}, of course, so that's no problem.

Have fun,
Thomas




More information about the Python-list mailing list