Reuben
Reuben

Reputation: 5736

Accessing dictionary of dictionary in python

Hi in my code there is a dictionary of dictionary.

nrec={'bridge': 'xapi1', 'current_operations': {}, 'uuid': '9ae5ca7d-e7d6-7a81-f619-d0ea33efb534', 'tags': [], 'other_config': {'is_guest_installer_network': 'true', 'netmask': '255.255.255.0', 'ip_end': '192.168.128.254', 'ip_begin': '192.168.128.1'}, 'name_label': 'Guest installer network', 'VIFs': ['OpaqueRef:dff106aa-1a94-8384-1c86-862b47c87fcf'], 'allowed_operations': [], 'PIFs': [], 'name_description': 'Network on which guests will get assigned a private local IP address', 'MTU': '1500', 'blobs': {}}

Here you can see inside this dictionary one more dictionary 'other_config': {'is_guest_installer_network': 'true', 'netmask': '255.255.255.0', 'ip_end': '192.168.128.254', 'ip_begin': '192.168.128.1'} is there.

I want to check is_guest_installer_network=="true"

I have done nrec["other_config"]["is_guest_installer_network"]== "true" but the problem is some attribute have this other_config property with either empty value or different value. Then in this case my solution will throw exception. So i want to do it in a efficient way like If is_guest_installer_network is consists in the dictionary and the value (string) is true or not.

Upvotes: 2

Views: 1005

Answers (7)

Ashwini Chaudhary
Ashwini Chaudhary

Reputation: 250891

Try this:

nrec["other_config"].get('is_guest_installer_network')

It'll return its value if 'is_guest_installer_network' exists in nrec['other_config']

Upvotes: 3

moooeeeep
moooeeeep

Reputation: 32502

If this is a config item, you shouldn't need to access it very often (thus your efficiency requirement would be questionable). Configure once and forget about it (e.g. set self.is_guest_installer_network = True).

If you can't forget about it, it would depend on the likelihood of the entry being present in your dictionary. If it's more likely that the item is missing it would probably be better if you do something like the following. You get some shortcut behavior if an item misses, the other config dict is looked up only once (for the existance check and for the value following lookup.

def check_guest_installer_network(nrec):
  other_config = nrec.get("other_config", None)
  return other_config is not None and other_config.get('is_guest_installer_network', False)

If it's more likely that the item is there, the lazy try/except approach could be better suited. As the saved check performance, would outweigh the additional performance cost when the exception actually needs to be handled.

def check_guest_installer_network(nrec):
  try:
    return nrec["other_config"]['is_guest_installer_network'] == "true"
  except KeyError:
    return False

After all, if this check indeed has a significant impact on the overall performance, you should put this variable somewhere it is better accessible, than in a nested dictionary, e.g. put it into a global/class member variable once, and enjoy the cheap and easy checks afterwards.

You should have a look at the cprofile module to verify that this lookup is indeed the bottleneck of your software, that is worth the optimization effort. And You should look at the timeit module to choose the most performant solution for your problem.

Upvotes: 3

CppLearner
CppLearner

Reputation: 17040

Your best bet to avoid exception is either try .. except, or use dictionary built-in methods.

my_dict = {'one': {'two': 'hello world!'}, 'four': 'Dummy!'}
try:
  my_name = my_dict['one']['two']
except:
  pass
  // instead of pass, you can also return something or do something else

try:
  my_dict['one']['two']
except Exception as e:
  my_name = 'default'
  return my_name, e  // returns a tuple which contains 'default' and error message


#or use has_key()

# this is for one-level nested dictionary
for id, items in my_dict.iteritems():
     if items.has_key('two'):
          //do something

# or simply this  --> eliminates dummy for loop
if my_dict['one'].has_key('two'):      // has_key returns True / False
      // do something

# or use in operator  (replace has_key)
if 'two' in my_dict['one'].keys():
     // do something


# or get method

my_dict['one'].get('two', 'Default')

Get is nice if that's all you need to avoid exception.

Upvotes: 0

dfb
dfb

Reputation: 13289

You've got the answer

nrec["other_config"]["is_guest_installer_network"]== "true"

can be written like

if nrec.has_key("other_config") and type(nrec["other_config"]) == type({}) and nrec["other_config"].has_key("....") and nrec["other_config"]["is_guest_installer_network"]== "true":

But this is sort of ugly.

Or, as noted in the comments

nrec.get("other_config",{}).get("is_guest_installer_network",{}) == "true"

But this doesn't handle the type checking.

Maybe best to do something like this

def traverse(_dict, keys):
    val = _dict
    for key in keys[:-1]:
        if key in val and type(val[key]) is dict :
            val = val[key]
        else:
            return None
    return val.get(keys[-1],None)

Upvotes: -1

Abhijit
Abhijit

Reputation: 63707

One possible solution is

>>> try:
    if nrec["other_config1"]["is_guest_installer_network"] == 'true':
        print 'Do Something'
except (KeyError,TypeError):
    None #Or do something logical

Upvotes: 0

Mariusz Jamro
Mariusz Jamro

Reputation: 31633

To check if a key exists in a dictionary use:

if 'key' in dictionary:
    # do sth

So your code will be:

if 'other_config' in nrec and 'is_guest_installer_network' in nrec['other_config'] and nrec['other_config']['is_guest_installer_network'] == 'true':
    # do sth

Additionally if you want default value if the key is not present in the dict use get(key, default) method:

nrec.get('other_config', default_value_here)

Upvotes: 0

Etienne Perot
Etienne Perot

Reputation: 4882

Just check

'other_config' in nrec and 'is_guest_installer_network' in nrec['other_config'] and nrec['other_config']['is_guest_installer_network'] == 'true'

Upvotes: 0

Related Questions