2

I want set the keys and values ​​in the dictionary. Here is an example of what I do.

class NestedDict(dict):
    def __getitem__(self, key):
        if key in self: return self.get(key)
        return self.setdefault(key, NestedDict())

>>> c = NestedDict()
>>> c
{}
>>> c['a']['b'] = 'test'
>>> c['a']['c'] = 2
>>> c
{'a': {'c': 2, 'b': 'test'}}
>>> c['a']['c'] += 1
>>> c
{'a': {'c': 3, 'b': 'test'}}
>>> c['a']['d'] += 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +=: 'NestedDict' and 'int'

Any ideas how to solve this problem? I want be able to use += and -=. Of course if value doesn't exist then += 1 is these same as = 1. Maybe there's a better solution?

Thanks.

eshlox
  • 766
  • 2
  • 11
  • 22
  • it's because your c['a']['d'] doesn't have a value, so your initiate it and want to increment something. juste do c['a']['d'] = 0 then you can to what you want – lpostula Mar 20 '12 at 09:21
  • 2
    when you write `c[someNonExistingKey] +=1`, what result would you want? – georg Mar 20 '12 at 09:26
  • i know, but i want write something that would automatically set 0 first if no value and is used =+ – eshlox Mar 20 '12 at 09:57
  • 1
    If I say `c[non_existing_key]`, should it return a `NestedDict` or `0`? – Noufal Ibrahim Mar 20 '12 at 10:39
  • Also see http://stackoverflow.com/questions/2435989/how-do-i-do-advanced-python-hash-autovivification – ncoghlan Aug 23 '12 at 12:24

3 Answers3

13

Since d is non existent in c['a'], what kind of behaviour do you expect when you try to add 1 to it? It will first call __getitem__, not find the key and then return a NestedDict which doesn't support in place addition with an int.

On a side note, It looks to me as though you're trying to implement a dictionary with a "default" value. I would use the defaultdict class available in the collections module like so

from collections import defaultdict

def create_nested_dict():
   return defaultdict(create_nested_dict)

c = create_nested_dict()
Noufal Ibrahim
  • 71,383
  • 13
  • 135
  • 169
2

Since you have control over your objects placed inside the nested dict, just define addition and subtraction to them in a way that when added to an object, it simply returns the other object (effectvely behaving as a numerical 0 when added to numbers):

class NestedDict(dict):
    def __getitem__(self, key):
        if key in self: return self.get(key)
        return self.setdefault(key, NestedDict())
    def __add__(self, other):
        return other
    def __sub__(self, other):
        return other

And voilá:

>>> n = NestedDict()
>>> n["a"]["b"] += 1
>>> n["a"]["b"]
1
jsbueno
  • 99,910
  • 10
  • 151
  • 209
1

First of all, setdefault() already returns self[key] if it exists, you don't need the first line of your __getitem__().

As for your problem, you can't do it. At least not with your existing code. You're already creating a NestedDict for every node that doesn't exist. Now you want some of them to be numbers?

Perhaps you should create a dynamic node class which could function either as a dict or as a number, depending on the need?

aib
  • 45,516
  • 10
  • 73
  • 79