Error message

  • Notice: Trying to get property of non-object in filter_default_format() (line 532 of /home/ntroutman/webapps/nt_drupal/modules/filter/filter.module).
  • Notice: Undefined variable: options in filter_process_format() (line 911 of /home/ntroutman/webapps/nt_drupal/modules/filter/filter.module).

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!

Comments

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?

 I had to enable contact info. So now people can leave such information.

Add new comment