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?

user1756095
  • 83
  • 2
  • 8

3 Answers3

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]
unutbu
  • 711,858
  • 148
  • 1,594
  • 1,547
  • @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? – Alan Franzoni Oct 19 '12 at 08:12
  • 1
    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 Oct 19 '12 at 08:56
  • @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. – Alan Franzoni Oct 19 '12 at 10:31
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?

Alan Franzoni
  • 2,758
  • 1
  • 18
  • 29
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)
Dhara
  • 5,937
  • 1
  • 29
  • 46