Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python: defaultdict with non-default argument

I want to have something like a dict of a class TestClass which has a non-default argument. When I access I don't know if the asked-for element came before already. So the 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 the dict and the accessing 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 testing code:

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

Nice. But I wonder if if there is a more elegant solution. Browsing, the defaultdict comes into my mind. But this won't work, because I cannot pass an argument to the default_factory:

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

gives TypeError: __init__() takes exactly 2 arguments (1 given)... I is there another solution?

Besides, I wanna improve my Python. So any other suggestions are welcome as well ;-)

like image 672
user3474620 Avatar asked Sep 20 '14 18:09

user3474620


People also ask

What is the default value in Defaultdict?

When the int class is passed as the default_factory argument, then a defaultdict is created with default value as zero.

Does Defaultdict work in Python?

A defaultdict works exactly like a normal dict, but it is initialized with a function (“default factory”) that takes no arguments and provides the default value for a nonexistent key. A defaultdict will never raise a KeyError. Any key that does not exist gets the value returned by the default factory.

Is Defaultdict faster than dict?

setdefault() , and the second uses a defaultdict . The time measure will depend on your current hardware, but you can see here that defaultdict is faster than dict.

What is Defaultdict int in Python?

Defaultdict is a container like dictionaries present in the module collections. Defaultdict is a sub-class of the dictionary class that returns a dictionary-like object. The functionality of both dictionaries and defaultdict are almost same except for the fact that defaultdict never raises a KeyError.


1 Answers

The defaultdict factory indeed does not take an argument.

You can create your own variant that does however; the trick is in defining a __missing__ method:

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

Whenever dict[key] is accessed for a non-existing key, the __missing__ method is called. defaultdict uses this hook to return factory() each time, but you can provide your own and pass in 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>}
like image 61
Martijn Pieters Avatar answered Oct 13 '22 16:10

Martijn Pieters