I have the following code:
from functions import *
powers = AutoVivification()
powers[1] = {'c1': 0.5, 'gamma': 1, 'lambda': 1, 'A': 1}
print powers[1]
my autovivification is the following (taken from: What is the best way to implement nested dictionaries?):
class AutoVivification(dict):
"""Implementation of perl's autovivification feature."""
def __getitem__(self, item):
try:
return dict.__getitem__(self, item)
except KeyError:
value = self[item] = type(self)()
return value
it prints the following:
{'A': 1, 'c1': 0.5, 'gamma': 1, 'lambda': 1}
notice the order has been changed. it's now alphabetical. is there any way to prevent this from happening? sory, wasn't clear enough: (without changing the keys, and using the property of autovivificaion of "making arbitrarilly expanding the dictionary super easy")
As the documentation says:
Keys and values are iterated over in an arbitrary order which is non-random, varies across Python implementations, and depends on the dictionary’s history of insertions and deletions.
In other words, dictionaries have no inherent order. And you can see that without all your complicated extras:
>>> print {'c1': 0.5, 'gamma': 1, 'lambda': 1, 'A': 1}
{'A': 1, 'c1': 0.5, 'gamma': 1, 'lambda': 1}
If you want a dict that maintains its keys in the order of insertion, you can do that with OrderedDict
.
However, that's not enough to help you in this case. If you construct a dict
(which has arbitrary order), then pass that to an OrderedDict
, all you're doing is freezing that initial arbitrary order:
>>> from collections import OrderedDict
>>> print OrderedDict({'c1': 0.5, 'gamma': 1, 'lambda': 1, 'A': 1})
OrderedDict([('A', 1), ('c1', 0.5), ('gamma', 1), ('lambda', 1)])
The repr
of that OrderedDict
should give you a clue to how you can create an OrderedDict
with an order for its initial values: create it from a sequence, where each element is a key-value pairs:
>>> print OrderedDict([('c1', 0.5), ('gamma', 1), ('lambda', 1), ('A', 1)])
OrderedDict([('c1', 0.5), ('gamma', 1), ('lambda', 1), ('A', 1)])
If you want to auto-vivify the OrderedDict
, you can do that by using OrderedDict
instead of dict
in your existing class. However, there are a few problems with the class you're using that you might want to consider. In particular, you really want to use super
rather than classic-style calls on parent-class methods; if you'd done that, you could just define class AutoVivifiedOrderedDict(OrderedDict, AutoVivification): pass
and be done with it! Also, I don't think your class will pickle properly as-is.
If you use a defaultdict
for autovivification, it's already taken care of all the tricky bits:
def AutoVivification():
return defaultdict(AutoVivification)
If you then want to add ordering to that, you will need an OrderedDefaultDict
, so you can do this:
def OrderedAutoVivification():
return OrderedDefaultDict(AutoVivification)
If you don't know how to create OrderedDefaultDict
yourself, search for recipes. (You can almost just inherit from both classes… except for the fact that they have different signatures, so you need to think through what your __init__
should look like and explicitly call the right base initializers with the right arguments. See this question for some discussion.)