|
""" |
|
EasyDict |
|
Copy/pasted from https://github.com/makinacorpus/easydict |
|
Original author: Mathieu Leplatre <[email protected]> |
|
""" |
|
|
|
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} |
|
>>> EasyDict((('a', 1), ('b', 2))) |
|
{'a': 1, 'b': 2} |
|
|
|
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 |
|
>>> list(map(attrgetter('x'), d.bar)) |
|
[1, 3] |
|
>>> list(map(attrgetter('y'), d.bar)) |
|
[2, 4] |
|
>>> d = EasyDict() |
|
>>> list(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}) |
|
>>> list(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 = {} |
|
else: |
|
d = dict(d) |
|
if kwargs: |
|
d.update(**kwargs) |
|
for k, v in d.items(): |
|
setattr(self, k, v) |
|
|
|
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): |
|
delattr(self, k) |
|
return super(EasyDict, self).pop(k, d) |
|
|
|
|
|
if __name__ == "__main__": |
|
import doctest |
|
doctest.testmod() |