"Extracting" a dictionary
Peter Otten
__peter__ at web.de
Thu May 20 12:52:30 EDT 2004
Noldoaran wrote:
> Arnold Filip:
>> How about this:
>>
>> In [1]: d = {'foo' : 23, 'bar' : 42}
>>
>> In [2]: for item in d.items():
>> ...: exec "%s = %d" % item
>> ...:
>>
>> In [3]: foo
>> Out[3]: 23
>>
>> In [4]: bar
>> Out[4]: 42
>
> you could extract them in to there own namespace:
>>>> class AttrDict:
> ... def __init__(self, d):
> ... self.__d = d
> ... def __getattr__(self,attr):
> ... return self.__d[attr]
> ... def __setattr__(self,attr,value):
> ... self.__d[attr] = value
> ... def __delattr__(self,attr):
> ... del self.__d[attr]
> ...
>>>> d = AttrDict({'foo' : 23, 'bar' : 42})
> Traceback (most recent call last):
> File "<input>", line 1, in ?
> File "<input>", line 3, in __init__
> File "<input>", line 10, in __setattr__
> (snip)
> RuntimeError: maximum recursion depth exceeded
>>>> d.foo
>
> That didn't work like I hoped. I decided to share it anyway in case
> someone can get it to work.
Saying self.__d = dont_care invokes __setattr__() to set __d, __setattr__()
asks __getattr__() for __d, which asks __getattr__() for __d to determine
__d ...ad infinitum.
To avoid the recursion you must bypass __setattr__() by accessing __dict__
directly (and do some name mangling due to the evil double-underscore
attribute name by hand):
>>> class AttrDict:
... def __init__(self, d):
... self.__dict__["_AttrDict__d"] = d
... def __getattr__(self, attr):
... return self.__d[attr]
... def __setattr__(self, attr, value):
... self.__d[attr] = value
... def __delattr__(self, attr):
... del self.__d[attr]
...
>>> d = AttrDict({'foo': 23, 'bar': 42})
>>> d.foo
23
>>> d.baz = 123
>>> d.foo = 456
>>> d.__d
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 5, in __getattr__
KeyError: '__d'
>>> d.AttrDict__d
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 5, in __getattr__
KeyError: 'AttrDict__d'
>>> d._AttrDict__d
{'baz': 123, 'foo': 456, 'bar': 42}
>>>
While this works, you can achieve the same functionality in a more elegant
way:
>>> class AttrDict:
... def __init__(self, d):
... self.__dict__.update(d)
...
>>> d = AttrDict({"foo": 23, "bar": 42})
>>> d.bar
42
>>> d.foo *= 2
>>> d.__dict__
{'foo': 46, 'bar': 42}
>>> del d.foo
>>> d.__dict__
{'bar': 42}
>>>
A standard trick, by the way. Can't think of the right google keywords right
now, so I use another standard trick and leave finding them as an excercise
to the reader :-)
Peter
More information about the Python-list
mailing list