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 :-)
source to share
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>}
source to share