content: class EasyDict(dict):
      """
      Get attributes
  
      >>> d = EasyDict({'foo':3})
      >>> d['foo']
      3
      >>> d.foo
      3
      >>> d.bar
      Traceback (most recent call last):
      ...
      AttributeError: 'EasyDict' object has no attribute 'bar'
  
      Works recursively
  
      >>> d = EasyDict({'foo':3, 'bar':{'x':1, 'y':2}})
      >>> isinstance(d.bar, dict)
      True
      >>> d.bar.x
      1
  
      Bullet-proof
  
      >>> EasyDict({})
      {}
      >>> EasyDict(d={})
      {}
      >>> EasyDict(None)
      {}
      >>> d = {'a': 1}
      >>> EasyDict(**d)
      {'a': 1}
  
      Set attributes
  
      >>> d = EasyDict()
      >>> d.foo = 3
      >>> d.foo
      3
      >>> d.bar = {'prop': 'value'}
      >>> d.bar.prop
      'value'
      >>> d
      {'foo': 3, 'bar': {'prop': 'value'}}
      >>> d.bar.prop = 'newer'
      >>> d.bar.prop
      'newer'
  
  
      Values extraction
  
      >>> d = EasyDict({'foo':0, 'bar':[{'x':1, 'y':2}, {'x':3, 'y':4}]})
      >>> isinstance(d.bar, list)
      True
      >>> from operator import attrgetter
      >>> map(attrgetter('x'), d.bar)
      [1, 3]
      >>> map(attrgetter('y'), d.bar)
      [2, 4]
      >>> d = EasyDict()
      >>> d.keys()
      []
      >>> d = EasyDict(foo=3, bar=dict(x=1, y=2))
      >>> d.foo
      3
      >>> d.bar.x
      1
  
      Still like a dict though
  
      >>> o = EasyDict({'clean':True})
      >>> o.items()
      [('clean', True)]
  
      And like a class
  
      >>> class Flower(EasyDict):
      ...     power = 1
      ...
      >>> f = Flower()
      >>> f.power
      1
      >>> f = Flower({'height': 12})
      >>> f.height
      12
      >>> f['power']
      1
      >>> sorted(f.keys())
      ['height', 'power']
  
      update and pop items
      >>> d = EasyDict(a=1, b='2')
      >>> e = EasyDict(c=3.0, a=9.0)
      >>> d.update(e)
      >>> d.c
      3.0
      >>> d['c']
      3.0
      >>> d.get('c')
      3.0
      >>> d.update(a=4, b=4)
      >>> d.b
      4
      >>> d.pop('a')
      4
      >>> d.a
      Traceback (most recent call last):
      ...
      AttributeError: 'EasyDict' object has no attribute 'a'
      """
  
      def __init__(self, d=None, **kwargs):
          if d is None:
              d = {}
          if kwargs:
              d.update(**kwargs)
          for k, v in d.items():
              setattr(self, k, v)
          # Class attributes
          for k in self.__class__.__dict__.keys():
              if not (k.startswith("__") and k.endswith("__")) and not k in ("update", "pop"):
                  setattr(self, k, getattr(self, k))
  
      def __setattr__(self, name, value):
          if isinstance(value, (list, tuple)):
              value = [self.__class__(x) if isinstance(x, dict) else x for x in value]
          elif isinstance(value, dict) and not isinstance(value, self.__class__):
              value = self.__class__(value)
          super(EasyDict, self).__setattr__(name, value)
          super(EasyDict, self).__setitem__(name, value)
  
      __setitem__ = __setattr__
  
      def update(self, e=None, **f):
          d = e or dict()
          d.update(f)
          for k in d:
              setattr(self, k, d[k])
  
      def pop(self, k, d=None):
          if hasattr(self, k):
              delattr(self, k)
          return super(EasyDict, self).pop(k, d)
  
  
  if __name__ == "__main__":
      import doctest
  
  