Binding a Lambda Function to an Object
So I needed to bind a lambda function to an object. I've been writing code that needs to run faster than it currently does and I've traced some slow-downs to repeated comparisons that are really wasted and things don't change once the object is instantiated. For instance below is an example to show you how one might code something (note this is just an example, not actual code)
class ThisIsAClass(object): def __init__(self, stat, value): self.stat = stat self.value = value def findMatches(self, attribs): matches = [] for attrib in attribs: if self.stat == 'mode': if attrib.stats[self.stat] == self.value: matches.append(attrib) elif self.stat == 'exact': if attrib.value == self.value: matches.append(attrib) else: if ttrib.stats[self.stat] >= self.value: matches.append(attrib) return matches
As you can see each time through the loop makes a comparison to self.stat which never changes once its set at instantiation. One way around this would be to define a lambda function for the correct stat type at instantiation and just call that in the loop. The problem is you just set a lambda function to an object it doesn't get self passed in when its called. For example,
>>> class Foo(object): pass >>> f = Foo() >>> f.bar = lambda self: (id(self), self) >>> f.bar() Traceback (most recent call last): File "", line 1, in TypeError: () takes exactly 1 argument (0 given)
So, how do we get around this? The cleanest is to use the fact functions are descriptors, so we can do this:
>>> f.car = f.bar.__get__(f, Foo) >>> f.car() (38415248, <__main__.Foo object at 0x24a2b90>)
This means our new class is defined like such:
class ThisIsAClass(object): def __init__(self, stat, value): self.stat = stat self.value = value if self.stat == 'mode': compare = lambda self, attrib: attrib.stats[self.stat] == self.value elif self.stat == 'exact': compare = lambda self, attrib: attrib.value == self.value else: compare = lambda self, attrib: attrib.stats[self.stat] >= self.value compare.__name__ = 'compare' compare = compare.__get__(self, ThisIsAClass) self.compare = compare def findMatches(self, attribs): matches = [] for attrib in attribs: if self.compare(attrib): matches.append(attribs) return matches
And there you go!
Delicious
Digg
StumbleUpon
Reddit
Facebook
I had to enable contact info. So now people can leave such information.
You couldn't just say the following, for example?
compare = lambda attrib: attrib.stats[self.stat] == self.value
Seems like that would let you access 'self' via the enclosing scope. Or does it not carry the right metadata that the function ought to have as a class method?
Can't say I've made full since of the '__get__' method, despite trying to read the docs on it, and my Python-fu is weak these days.
In that example with the functions being nested it probably isn't needed to actually pass self in as the closure would probably capture it. However, in the trivial example I gave the method is used for attaching a function to object without being the scope of that objects methods.
Thanks for the comment, means people occasionally actually read what I write.
Just occurred to me there was no author field there. I wasn't paying close attention beforehand. This is Tom Palmer, in case you were curious. Sorry if that makes it less exciting. But you might have more distant readership, too. Do you keep stats, by chance?
Post new comment