Skip to content Skip to sidebar Skip to footer

Python Chained Get() Method With List Element Inside Json

[Python 2.7] I have a JSON source that doesn't always return the full list of expected keys. I'm using chained gets() to address this. d = {'a': {'b': 1}} print(d.get('a', {}).get

Solution 1:

I agree with @stovfl that writing your own lookup function is the way to go. Although, I don't think a recursive implementation is necessary. The following should work well enough:

def nested_lookup(obj, keys, default='NA'):
    current = obj
    for key in keys:
        current = current if isinstance(current, list) else [current]
        try:
            current = next(sub[key] forsubincurrentifkeyinsub)
        exceptStopIteration:
            returndefaultreturncurrentd = {'a': {'b': [{'c': 2}, {'d': 3}]}}

print nested_lookup(d, ('a', 'b', 'c'))  # 2print nested_lookup(d, ('a', 'b', 'd'))  # 3print nested_lookup(d, ('a', 'c'))       # NA

The class approach doesn't seem great because you're going to be creating a lot of unnecessary objects and if you're ever trying to lookup a node that isn't a leaf, then you're going to wind up with a custom object rather than the actual node object.

Solution 2:

Question: I can't use a get() ... because lists don't support the get().

  1. You can implement your own list.get(), for instance:

    classmyGET(object):
        def__init__(self, data):
            ifisinstance(data, dict):
                self.__dict__.update(data)
            ifisinstance(data, list):
                for d in data:
                    self.__dict__.update(d)
    
        defget(self, key, default=None):
            ifhasattr(self, key):
                _attr = object.__getattribute__(self, key)
                ifisinstance(_attr, (list, dict)):
                    return myGET(_attr)
                else:
                    return _attr
            else:
                return default
    
    d = {'a': {'b': [{'c': 2}]}}
    myGET(d).get('a', {}).get('b', []).get('c', 'NA')
    >>> 2
    
    myGET(d).get('a', {}).get('b', []).get('d', 'NA')
    >>> NA
    
  2. A recursive Solution, no need to chaining, for instance:

    defget(_dict, subkey, default):
        def_get(_dict, key, deep):
            if key == subkey[deep]:
                if deep == len(subkey) - 1:
                    return _dictelse:
                    return _get(_dict, None, deep + 1)
    
            elifisinstance(_dict, dict):
                for k in _dict:
                    match = _get(_dict[k], k, deep)
                    if match: return match
    
            elifisinstance(_dict, list):
                for e in _dict:
                    match = _get(e, None, deep)
                    if match: return match
    
        ifnotisinstance(subkey, (tuple, list)):
            subkey = (subkey)
    
        _r = _get(_dict, None, 0)
        ifnot _r: return default
        else:      return _r
    
    get(d, 'c', 'NA')
    >>> 2
    
    get(d, 'd', 'NA')
    >>> NA
    
    # get a inside b
    d = {'a': {'b': [{'a': 3}, {'c': 2}]}}
    get(d, ('b', 'a'), 'NA')
    >>> 3

Tested with Python: 3.4.2 and 2.7.9

Post a Comment for "Python Chained Get() Method With List Element Inside Json"