I find it more conveniant to access dict keys as obj.foo
instead of obj['foo']
, so I wrote this snippet:
class AttributeDict(dict):
def __getattr__(self, attr):
return self[attr]
def __setattr__(self, attr, value):
self[attr] = value
However, I assume there must be some reason that Python doesn't provide this functionality out of the box. What would be the caveats and pitfalls of accessing dict keys in this manner?
What if you wanted a key which was a method, such as
__eq__
or__getattr__
?And you wouldn't be able to have an entry that didn't start with a letter, so using
0343853
as a key is out.And what if you didn't want to use a string?
Wherein I Answer the Question That Was Asked
Why doesn't Python offer it out of the box?
I suspect that it has to do with the Zen of Python: "There should be one -- and preferably only one -- obvious way to do it." This would create two obvious ways to access values from dictionaries:
obj['key']
andobj.key
.Caveats and Pitfalls
These include possible lack of clarity and confusion in the code. i.e., the following could be confusing to someone else who is going in to maintain your code at a later date, or even to you, if you're not going back into it for awhile. Again, from Zen: "Readability counts!"
If
d
is instantiated orKEY
is defined ord[KEY]
is assigned far away from whered.spam
is being used, it can easily lead to confusion about what's being done, since this isn't a commonly-used idiom. I know it would have the potential to confuse me.Additonally, if you change the value of
KEY
as follows (but miss changingd.spam
), you now get:IMO, not worth the effort.
Other Items
As others have noted, you can use any hashable object (not just a string) as a dict key. For example,
is legal, but
is not. This gives you access to the entire range of printable characters or other hashable objects for your dictionary keys, which you do not have when accessing an object attribute. This makes possible such magic as a cached object metaclass, like the recipe from the Python Cookbook (Ch. 9).
Wherein I Editorialize
I prefer the aesthetics of
spam.eggs
overspam['eggs']
(I think it looks cleaner), and I really started craving this functionality when I met thenamedtuple
. But the convenience of being able to do the following trumps it.This is a simple example, but I frequently find myself using dicts in different situations than I'd use
obj.key
notation (i.e., when I need to read prefs in from an XML file). In other cases, where I'm tempted to instantiate a dynamic class and slap some attributes on it for aesthetic reasons, I continue to use a dict for consistency in order to enhance readability.I'm sure the OP has long-since resolved this to his satisfaction, but if he still wants this functionality, then I suggest he download one of the packages from pypi that provides it:
Bunch is the one I'm more familiar with. Subclass ofdict
, so you have all that functionality.However, in order to improve readability of his code I strongly recommend that he not mix his notation styles. If he prefers this notation then he should simply instantiate a dynamic object, add his desired attributes to it, and call it a day:
Wherein I Update, to Answer a Follow-Up Question in the Comments
In the comments (below), Elmo asks:
While I've never used this use case (again, I tend to use nested
dict
, for consistency), the following code works:This doesn't address the original question, but should be useful for people that, like me, end up here when looking for a lib that provides this functionality.
Addict it's a great lib for this: https://github.com/mewwts/addict it takes care of many concerns mentioned in previous answers.
An example from the docs:
With addict:
You can do it using this class I just made. With this class you can use the
Map
object like another dictionary(including json serialization) or with the dot notation. I hope help you:Usage examples:
As noted by Doug there's a Bunch package which you can use to achieve the
obj.key
functionality. Actually there's a newer version calledNeoBunch
It has though a great feature converting your dict to a NeoBunch object through its neobunchify function. I use Mako templates a lot and passing data as NeoBunch objects makes them far more readable, so if you happen to end up using a normal dict in your Python program but want the dot notation in a Mako template you can use it that way:
And the Mako template could look like:
Let me post another implementation, which builds upon the answer of Kinvais, but integrates ideas from the AttributeDict proposed in http://databio.org/posts/python_AttributeDict.html.
The advantage of this version is that it also works for nested dictionaries: