views:

51

answers:

2

Hi,

I was trying to 'extend' a closed class

collections.defaultdict(lambda: 1)

by addint it 2 methods, called 'vocabulary', and 'wordcount' apparently it's impossible to setattr method to builin types, nor can I inherit from defaultdic, so I decided to write a class and redirect calls to it to the type I want to extend.

class BagOfWordDoc():
    def __init__(self):
        self.data = collections.defaultdict(lambda: 1)
        for method in dir(self.data):
            if hasattr(getattr(self.data, method),'__call__') and method not in ['__class__', '__self__']:
                l = lambda *args: getattr(self.data, method)(*args)
                setattr(self, method,l)

    def vocabulary(self):
        return self.data.keys()

    def wordcount(self):
        return reduce(operator.add, self.data.values(), 0) 

However it shows upon accessing it

 doc = BagOfWordDoc()
 doc[123]   = 123          # yields TypeError: values() takes no arguments (1 given)
 doc.keys()                # yields TypeError: values() takes no arguments (1 given)
 doc.xxx()                 # yields TypeError: values() takes no arguments (1 given)

So it'is as if every lambda was mapped to the 'values' function And 'values' is the last element of the property list

Do you know why this happens ? As for the initial problem, I am now thinking of rewriting my own defaultdict.

update

Based on the suggestion made, hereis the working implementation :

class BagOfWordDoc():
    def __init__(self):
        self.data = collections.defaultdict(lambda: 0)

    def __getattr__(self, *args):
        return self.data.__getattribute__(*args)

    def vocabulary(self):
        return self.data.keys()

    def wordcount(self):
        return reduce(operator.add, self.data.values(), 0) 
+3  A: 

Either copy from class to class, not instance to instance, or just have .__getattr__() delegate to the encapsulated object.

Ignacio Vazquez-Abrams
overriding __getattr__ seems to work. thank you.Regarding this lambda construct, do you any idea how I can capture the state of the variable 'method' at each lambda definition instead of having them all pointing to the last value ("values") ?
nicolas
http://code.activestate.com/recipes/502271/
Ignacio Vazquez-Abrams
+1  A: 

What do you mean with "cannot inherit from defaultdict"? It works for me (not a very good example, but I'm not sure what you're trying to accomplish, so...):

#!/usr/bin/env python


from collections import defaultdict
import operator


class DD(defaultdict):

   def vocabulary(self):
        return self.keys()

    def wordcount(self):
        return reduce(operator.add, self.data.itervalues(), 0)


if __name__ == '__main__':
    dd = DD(int)

    dd[2] += 1
    print dd.vocabulary()
mzz