Since you say that most of the queries will be resolved by looking at the first dict, your fastest solution would be to do something like:
try:
item = d1[key]
except KeyError:
try:
item = d2[key]
except KeyError:
...
However, that is certainly not the most maintainable of solutions and I don't recommend using it. You could create a function:
def get_from(item,dicts):
for d in dicts:
try:
return d[item]
except KeyError:
pass
else:
raise KeyError("No item in dicts")
which you would call like:
get_from(key,(d1,d2,d3))
(this is a simplified, slightly less clean, version of the already very simple Chained map recipe suggested by @MartijnPieters in the comments on the original question -- I would advocate using that over this code posted here. This code is only to demonstrate the concept in a more simplified way.)
Finally, perhaps a hybrid solution would work best in practice. Factor the first try
out of the loop -- This is a little ugly, but it avoids the overhead of the loop
most of the time. Only if the first try
raises a KeyError
do you enter the loop type solution I suggested above on the remaining dicts. e.g.:
try:
item = d1[key]
except KeyError:
item = get_from(key,(d2,d3))
again, only do this if you can reliably demonstrate (think timeit
) that it makes a measureable difference
The important thing to know is that in python, try
is cheap, but except
costs a decent amount of time. If your code is expected to succeed, use try
-except
. If it isn't expected to succeed, often it's best to use try-except
anyway, but in that case, you should evaluate whether performance is really an issue and only if you can demonstrate that it is an issue should you resort to "looking before you leap".
One final note, If the dictionaries are relatively static, it might be worth combining them into 1 dict
:
d1.update(d2)
d1.update(d3)
Now you can just use d1
-- It has all the information from d2
and d3
. (of course, the order of the updates matters if the dicts have keys that are the same but have different values).