3

I have a dict subclass whose job is to dynamically add nested dict key if it not exists and do list append if append is called:

class PowerDict(dict):
    def __getitem__(self, item):
        try:
            return dict.__getitem__(self, item)
        except KeyError:
            value = self[item] = type(self)()
            return value
    def append(self,item):
        if type(self) != list:
            self = list()
            self.append(item)

so

a = PowerDict()
a['1']['2'] = 3

produce output:

a = {'1': {'2': 3}}

However, sometime i need to do something like this:

b = PowerDict()
b['1']['2'].append(3)
b['1']['2'].append(4)

should produce output:

b = {'1': {'2': [3, 4]}}

but above code produce output:

{'1': {'2': {}}}

What i am missing?

3
  • 3
    you cant say self=list() ... you need to set the key equal to a list... self is a dict Commented Oct 18, 2012 at 15:25
  • 3
    Indeed, self = list() just rebinds the variable self. Commented Oct 18, 2012 at 15:26
  • 1
    Are you attached to the multiple-indexing format? I find a dictonary indexed by tuples rather more elegant: a[1,2]=3. Commented Oct 18, 2012 at 15:31

3 Answers 3

1
class PowerDict(dict):
    # http://stackoverflow.com/a/3405143/190597 (gnibbler)
    def __init__(self, parent = None, key = None):
        self.parent = parent
        self.key = key
    def __missing__(self, key):
        self[key] = PowerDict(self, key)
        return self[key]
    def append(self, item):
        self.parent[self.key] = [item]
    def __setitem__(self, key, val):
        dict.__setitem__(self, key, val)
        try:
            val.parent = self
            val.key = key
        except AttributeError:
            pass

a = PowerDict()
a['1']['2'] = 3
print(a)

b = PowerDict()
b['1']['2'].append(3)
b['1']['2'].append(4)
print(b)

a['1']['2'] = b
a['1']['2'].append(5)
print(a['1']['2'])

yields

{'1': {'2': 3}}
{'1': {'2': [3, 4]}}
[5]
Sign up to request clarification or add additional context in comments.

3 Comments

@unutbu I strongly disagree with such idea. When "traversing" such "powerdict", you'll never know which type you'll be using (unless you'll use an "isinstance" for that, which is usually considered not a good practice). How do you know how to handle values you fetch from the dictionary?
There are reasons to not like PowerDict -- especially the potential bugginess of __setitem__. But traversal is a problem not unique to PowerDict. Your objection applies equally well to plain nested dicts: {'1': {'2': [3, 4], ...}}. What I wanted to show in this post was that it was possible to implement an object with the desired syntactic sugar. The question of advisability depends on context. Is this just for learning or for production code? Since the OP did not state, I did not advise.
@unutbu yet the poster is probably inexperienced enough to need an advice about what to do and what not to do, not just a working implementation for a probably bad idea.
0

Your append() method never works. By doing self = list() you're just reassigning the name self to a new list, which is then thrown away.

And I don't understand what you're trying to do - from getitem, you're creating new dictionaries on-the-fly if something is missing... how would you mix list behaviour in?

Comments

0

One of your problems is reassigning self, however, that's not it. Try printing out the value of self in the append command, and you can see another problems: The loop enters an infinite recursion. This is because you're calling the append command on a powerDict in your append command!

This should solve your problem without re-writing the append command, but I strongly suggest you re-write it anyway to avoid the above-mentioned problem:

b['1']['2']= [3]
b['1']['2'].append(4)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.