JSON中包含列表元素的Python链式get()方法

JSON中包含列表元素的Python链式get()方法,python,json,python-2.7,list,dictionary,Python,Json,Python 2.7,List,Dictionary,[Python 2.7] 我有一个JSON源代码,它并不总是返回预期键的完整列表。我使用chained get()来解决这个问题 d = {'a': {'b': 1}} print(d.get('a', {}).get('b', 'NA')) print(d.get('a', {}).get('c', 'NA')) >>> 1 >>> NA 然而,一些格言在列表中: d = {'a': {'b': [{'c': 2}]}} print(d['a']['

[Python 2.7]

我有一个JSON源代码,它并不总是返回预期键的完整列表。我使用chained get()来解决这个问题

d = {'a': {'b': 1}}

print(d.get('a', {}).get('b', 'NA'))
print(d.get('a', {}).get('c', 'NA'))

>>> 1
>>> NA
然而,一些格言在列表中:

d = {'a': {'b': [{'c': 2}]}}

print(d['a']['b'][0]['c'])

>>> 2
我无法使用get()方法对此进行解释,因为列表不支持get()属性:

d.get('a', {}).get('b', []).get('c', 'NA')

>>> AttributeError: 'list' object has no attribute 'get'
除了捕获数百个潜在的键错误之外,是否有一种首选方法来解释潜在的缺失
['c']
(与上面的链式get()构造类似)

问题:我不能使用get()。。。因为列表不支持get()

  • 您可以实现自己的
    列表。get()
    ,例如:

    class myGET(object):
        def __init__(self, data):
            if isinstance(data, dict):
                self.__dict__.update(data)
            if isinstance(data, list):
                for d in data:
                    self.__dict__.update(d)
    
        def get(self, key, default=None):
            if hasattr(self, key):
                _attr = object.__getattribute__(self, key)
                if isinstance(_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
    
    def get(_dict, subkey, default):
        def _get(_dict, key, deep):
            if key == subkey[deep]:
                if deep == len(subkey) - 1:
                    return _dict
                else:
                    return _get(_dict, None, deep + 1)
    
            elif isinstance(_dict, dict):
                for k in _dict:
                    match = _get(_dict[k], k, deep)
                    if match: return match
    
            elif isinstance(_dict, list):
                for e in _dict:
                    match = _get(e, None, deep)
                    if match: return match
    
        if not isinstance(subkey, (tuple, list)):
            subkey = (subkey)
    
        _r = _get(_dict, None, 0)
        if not _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
    
  • 递归解决方案,无需链接,例如:

    class myGET(object):
        def __init__(self, data):
            if isinstance(data, dict):
                self.__dict__.update(data)
            if isinstance(data, list):
                for d in data:
                    self.__dict__.update(d)
    
        def get(self, key, default=None):
            if hasattr(self, key):
                _attr = object.__getattribute__(self, key)
                if isinstance(_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
    
    def get(_dict, subkey, default):
        def _get(_dict, key, deep):
            if key == subkey[deep]:
                if deep == len(subkey) - 1:
                    return _dict
                else:
                    return _get(_dict, None, deep + 1)
    
            elif isinstance(_dict, dict):
                for k in _dict:
                    match = _get(_dict[k], k, deep)
                    if match: return match
    
            elif isinstance(_dict, list):
                for e in _dict:
                    match = _get(e, None, deep)
                    if match: return match
    
        if not isinstance(subkey, (tuple, list)):
            subkey = (subkey)
    
        _r = _get(_dict, None, 0)
        if not _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
    
  • 用Python测试:3.4.2和2.7.9

    问题:我不能使用get()。。。因为列表不支持get()

  • 您可以实现自己的
    列表。get()
    ,例如:

    class myGET(object):
        def __init__(self, data):
            if isinstance(data, dict):
                self.__dict__.update(data)
            if isinstance(data, list):
                for d in data:
                    self.__dict__.update(d)
    
        def get(self, key, default=None):
            if hasattr(self, key):
                _attr = object.__getattribute__(self, key)
                if isinstance(_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
    
    def get(_dict, subkey, default):
        def _get(_dict, key, deep):
            if key == subkey[deep]:
                if deep == len(subkey) - 1:
                    return _dict
                else:
                    return _get(_dict, None, deep + 1)
    
            elif isinstance(_dict, dict):
                for k in _dict:
                    match = _get(_dict[k], k, deep)
                    if match: return match
    
            elif isinstance(_dict, list):
                for e in _dict:
                    match = _get(e, None, deep)
                    if match: return match
    
        if not isinstance(subkey, (tuple, list)):
            subkey = (subkey)
    
        _r = _get(_dict, None, 0)
        if not _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
    
  • 递归解决方案,无需链接,例如:

    class myGET(object):
        def __init__(self, data):
            if isinstance(data, dict):
                self.__dict__.update(data)
            if isinstance(data, list):
                for d in data:
                    self.__dict__.update(d)
    
        def get(self, key, default=None):
            if hasattr(self, key):
                _attr = object.__getattribute__(self, key)
                if isinstance(_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
    
    def get(_dict, subkey, default):
        def _get(_dict, key, deep):
            if key == subkey[deep]:
                if deep == len(subkey) - 1:
                    return _dict
                else:
                    return _get(_dict, None, deep + 1)
    
            elif isinstance(_dict, dict):
                for k in _dict:
                    match = _get(_dict[k], k, deep)
                    if match: return match
    
            elif isinstance(_dict, list):
                for e in _dict:
                    match = _get(e, None, deep)
                    if match: return match
    
        if not isinstance(subkey, (tuple, list)):
            subkey = (subkey)
    
        _r = _get(_dict, None, 0)
        if not _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
    

  • 用Python测试:3.4.2和2.7.9

    我同意@stovfl的观点,编写自己的查找函数是一条可行之路。尽管如此,我不认为递归实现是必要的。以下几点应该足够有效:

    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] for sub in current if key in sub)
            except StopIteration:
                return default
        return current
    
    
    d = {'a': {'b': [{'c': 2}, {'d': 3}]}}
    
    print nested_lookup(d, ('a', 'b', 'c'))  # 2
    print nested_lookup(d, ('a', 'b', 'd'))  # 3
    print nested_lookup(d, ('a', 'c'))       # NA
    

    类方法看起来不太好,因为您将创建许多不必要的对象,如果您试图查找一个不是叶的节点,那么您将得到一个自定义对象,而不是实际的节点对象。

    我同意@stovfl的观点,编写您自己的查找函数是一种方法。尽管如此,我不认为递归实现是必要的。以下几点应该足够有效:

    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] for sub in current if key in sub)
            except StopIteration:
                return default
        return current
    
    
    d = {'a': {'b': [{'c': 2}, {'d': 3}]}}
    
    print nested_lookup(d, ('a', 'b', 'c'))  # 2
    print nested_lookup(d, ('a', 'b', 'd'))  # 3
    print nested_lookup(d, ('a', 'c'))       # NA
    

    类方法看起来不太好,因为您将创建许多不必要的对象,如果您试图查找一个不是叶的节点,那么您将得到一个自定义对象,而不是实际的节点对象。

    .get('b',[{}])[0]
    ,可能吧?“除了捕获数百个潜在的关键错误,[…]“试一试<代码>有什么问题:。。。除了:?@jornsharpe:谢谢。这就是我要找的。请考虑将此作为问题的答案。@ RAWIN:在OP中回答。我希望避免使用数百个尝试块。我尝试了一次递归,但是考虑到源代码的复杂性,它变得太笨拙了。我不明白为什么您需要不止一个
    try
    块。编写一个函数来检索所需的dict/list项,如果出现异常,则返回一个默认值。
    .get('b',[{}])[0]
    ,也许吧?“除了捕获数百个潜在的键错误,[…]”a
    有什么问题吗。。。除了:
    ?@jornsharpe:谢谢。这就是我要找的。请考虑将此作为问题的答案。@ RAWIN:在OP中回答。我希望避免使用数百个尝试块。我尝试了一次递归,但是考虑到源代码的复杂性,它变得太笨拙了。我不明白为什么您需要不止一个
    try
    块。编写一个函数来检索所需的dict/list项,如果引发异常,则返回一个默认值。谢谢。你的第一个例子给了我一个例外,但第二个很好。错误(Python2 vs 3?):
    回溯(最近一次调用):myGET(d).get('a',{}).get('b',[])中的文件“untitled text 21”,第23行。get('c','NA')文件“untitled text 21”,第14行,在get_attr=object中。uuuuuuuu getattribute(self,key)AttributeError:'instance'对象没有属性'a'
    @DaveL17:是一个2.7问题,缺少子类<代码>类myGET(对象):,已修复。谢谢。你的第一个例子给了我一个例外,但第二个很好。错误(Python2 vs 3?):
    回溯(最近一次调用):myGET(d).get('a',{}).get('b',[])中的文件“untitled text 21”,第23行。get('c','NA')文件“untitled text 21”,第14行,在get_attr=object中。uuuuuuuu getattribute(self,key)AttributeError:'instance'对象没有属性'a'
    @DaveL17:是一个2.7问题,缺少子类<代码>类myGET(对象):,已修复。谢谢。它工作得很好,看起来很简单。尽管@stovfl的第二个例子也很有效,我还是会接受这个答案。我自己无法提出一个令人满意的函数,因此无法执行Rawing提出的将其移动到函数的建议。谢谢。它工作得很好,看起来很简单。尽管@stovfl的第二个例子也很有效,我还是会接受这个答案。我自己无法提出一个令人满意的函数,因此无法实现Rawing提出的将其移动到函数的建议。