Python: defaultdict with non-default argument

I want to have something like dict

for class TestClass

that has a non-default argument. When I access, I don't know if the previously requested item has appeared. So TestClass

:

class TestClass(object):
    def __init__(self, name):
        self.name = name
        self.state = 0
    def getName(self):
        self.state = self.state + 1
        return "%s -- %i" % (self.name, self.state)

      

Then dict

and the access function:

db = {}
def getOutput(key):
    # this is a marvel in the world of programming langauges
    if key not in db:
        db[key] = TestClass(key)
    return db[key]

      

And the actual test code:

if __name__ == "__main__":
    print "testing: %s" % getOutput('charlie').getName()

      

Nice. But I am wondering if there is a more elegant solution. Viewing, defaultdict comes to my mind. But that won't work because I can't pass the default_factory argument :

from collections import defaultdict
d = defaultdict(TestClass)
print "testing %s" % d['tom'].getOutput()

      

gives TypeError: __init__() takes exactly 2 arguments (1 given)

... am I there another solution?

Also, I want to improve my Python. So any other suggestions are appreciated :-)

+3


source to share


1 answer


defaultdict

factory doesn't really take an argument.

However, you can create your own; the trick is to define the method __missing__

:

class TestClassDict(dict):
    def __missing__(self, key):
        res = self[key] = TestClass(key)
        return res

      



When accessing dict[key]

for a nonexistent one key

, the method is called __missing__

. defaultdict

uses this hook to return factory()

every time, but you can provide your own and transfer key

.

Demo:

>>> class TestClass(object):
...     def __init__(self, name):
...         self.name = name
...         self.state = 0
...     def getName(self):
...         self.state = self.state + 1
...         return "%s -- %i" % (self.name, self.state)
... 
>>> class TestClassDict(dict):
...     def __missing__(self, key):
...         res = self[key] = TestClass(key)
...         return res
... 
>>> db = TestClassDict()
>>> db['charlie'].getName()
'charlie -- 1'
>>> db
{'charlie': <__main__.TestClass object at 0x102f72250>}

      

+4


source







All Articles