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 -- http://mail.python.org/mailman/listinfo/python-list