3

I want to make a dict int which you can access like that:

>>> my_dict["property'] = 3
>>> my_dict.property
3

So I've made this one:

class DictAsMember(dict):
    def __getattr__(self, name):
        return self[name]

This works fine, but if you have nested dicts it doesn't work, e.g:

my_dict = DictAsMember()
my_dict["property"] = {'sub': 1}

I can access to my_dict.property but logically I can't do my_dict.property.sub because property is a default dict, so what i want to do it's overwrite the default dict, so you can use {}.

Is this possible?

Félix
  • 579
  • 4
  • 21

2 Answers2

7

One workaround to the problem is wrapping default dictionaries using DictAsMember before returning them in the __getattr__ method:

class DictAsMember(dict):
    def __getattr__(self, name):
        value = self[name]
        if isinstance(value, dict):
            value = DictAsMember(value)
        elif isinstance(value, list):
            value = [DictAsMember(element)
                     if isinstance(element, dict)
                     else element
                     for element in value]

        return value

my_dict = DictAsMember()
my_dict["property"] = {'sub': 1}
print my_dict.property.sub    # 1 will be printed

my_dict = DictAsMember()
my_dict["property"] = [{'name': 1}, {'name': 2}]
print my_dict.property[1].name    # 2 will be printed
jcollado
  • 39,419
  • 8
  • 102
  • 133
  • The only problem that i find with that is if you have an array with dicts, e.g: my_dict["properties"] = [{'name': 1}, {'name':2}] Yo can modify the workaround so it takes into account the arrays, that's why i was looking for a way to overwrite the default dict – Félix Jan 03 '12 at 09:46
  • @Félix Things will get a little more complex, but dictionaries inside lists can still be wrapped. I've updated my answer to show an example using dictionaries inside a list. – jcollado Jan 03 '12 at 10:06
2

Rather than writing your own class to implement the my_dict.property notation (this is called object notation) you could instead use named tuples. Named tuple can be referenced using object like variable deferencing or the standard tuple syntax. From the documentation

The [named tuple] is used to create tuple-like objects that have fields accessible by attribute lookup as well as being indexable and iterable.

As an example of their use:

from collections import *

my_structure = namedtuple('my_structure', ['name', 'property'])
my_property  = namedtuple('my_property', ['sub'])

s = my_structure('fred', my_property(1))

s # my_structure(name='fred', property=my_property(sub=1)) will be printed

s.name # 'fred' will be printed

s.property # my_property(sub=1) will be printed

s.property.sub # 1 will be printed

See also the accepted answer to this question for a nice summary of named tuples.

Community
  • 1
  • 1
Chris
  • 44,602
  • 16
  • 137
  • 156