【问题标题】:'NoneType' is not iterable while recursively parsing a dict?'NoneType' 在递归解析字典时不可迭代?
【发布时间】:2019-12-08 01:43:37
【问题描述】:

使用此功能:

def extract_flat_branch(nested_dict, c = []):
    for i in ['left', 'op', 'right', 'func', 'value', 'args', 
              'ctx', 'body', 'comparators', 'ops', 'test', 'orelse', 'targets', 'slice']:
        if i in nested_dict:
            if isinstance(nested_dict[i], list):
                for b in nested_dict[i]:
                    yield from extract_flat_branch(b, c+[nested_dict['_type']]) 
            else:
                yield from extract_flat_branch(nested_dict[i], c+[nested_dict['_type']]) 
    lis = [c+[nested_dict['_type'], i] for i in filter(None, [nested_dict.get(j) for j in ['n', 'id']])]
    yield from lis if lis else [c+[nested_dict['_type']]] if len(nested_dict) == 1 else []

我正在遍历并提取表示为该字典 (my_dict) 的这棵树的分支,作为字符串列表,其中树的所有分支都是平面列表的元素。但是,出于某种原因,当我这样做时:

在:

print(list(extract_flat_branch(my_dict)))

而不是得到类似这样的输出:

[[node_1, node_2, .., node_n],[node_1, node_2, .., node_n],...,[node_1, node_2, .., node_n]]

我得到:

TypeError: argument of type 'NoneType' is not iterable

基于这个blog,我认为问题是我正在使用的.get(j)。但是,如果我这样做nested_dict.get(j) or {} for j in ['n', 'id']]),我仍然会得到相同的TypeError。知道如何解决此问题并获得树分支的平面列表吗?

这是完整的跟踪

TypeError                                 Traceback (most recent call last)
<ipython-input-4-51bfd7bbf4e4> in <module>
      1 for i,j in enumerate(a_lis):
      2     print(i)
----> 3     print(list(extract_flat_branch(j)))

~/dir/util.py in extract_flat_branch(nested_dict, c)
     38             if isinstance(nested_dict[i], list):
     39                 for b in nested_dict[i]:
---> 40                     yield from extract_flat_branch(b, c+[nested_dict['_type']])
     41             else:
     42                 yield from extract_flat_branch(nested_dict[i], c+[nested_dict['_type']])

~/dir/util.py in extract_flat_branch(nested_dict, c)
     38             if isinstance(nested_dict[i], list):
     39                 for b in nested_dict[i]:
---> 40                     yield from extract_flat_branch(b, c+[nested_dict['_type']])
     41             else:
     42                 yield from extract_flat_branch(nested_dict[i], c+[nested_dict['_type']])

~/dir/util.py in extract_flat_branch(nested_dict, c)
     40                     yield from extract_flat_branch(b, c+[nested_dict['_type']])
     41             else:
---> 42                 yield from extract_flat_branch(nested_dict[i], c+[nested_dict['_type']])
     43     lis = [c+[nested_dict['_type'], i] for i in filter(None, [nested_dict.get(j) for j in ['n', 'id']])]
     44     yield from lis if lis else [c+[nested_dict['_type']]] if len(nested_dict) == 1 else []

~/dir/util.py in extract_flat_branch(nested_dict, c)
     38             if isinstance(nested_dict[i], list):
     39                 for b in nested_dict[i]:
---> 40                     yield from extract_flat_branch(b, c+[nested_dict['_type']])
     41             else:
     42                 yield from extract_flat_branch(nested_dict[i], c+[nested_dict['_type']])

~/dir/util.py in extract_flat_branch(nested_dict, c)
     40                     yield from extract_flat_branch(b, c+[nested_dict['_type']])
     41             else:
---> 42                 yield from extract_flat_branch(nested_dict[i], c+[nested_dict['_type']])
     43     lis = [c+[nested_dict['_type'], i] for i in filter(None, [nested_dict.get(j) for j in ['n', 'id']])]
     44     yield from lis if lis else [c+[nested_dict['_type']]] if len(nested_dict) == 1 else []

~/dir/util.py in extract_flat_branch(nested_dict, c)
     35     for i in ['left', 'op', 'right', 'func', 'value', 'args', 
     36               'ctx', 'body', 'comparators', 'ops', 'test', 'orelse', 'targets', 'slice']:
---> 37         if i in nested_dict:
     38             if isinstance(nested_dict[i], list):
     39                 for b in nested_dict[i]:

TypeError: argument of type 'NoneType' is not iterable

【问题讨论】:

  • @00,我添加了完整的跟踪,感谢您的帮助

标签: python dictionary recursion data-structures


【解决方案1】:

出现NoneType 错误是因为在您的数据中有一个特定的"value" 键,该键被散列到相应的None"value" 是函数签名下方的键列表中的目标键,当前逻辑尝试检查函数输入 nested_dict 中是否存在任何此类键。对于具有 None 值的目标键,您需要的输出是什么尚不清楚,但一个简单的解决方法是检查并忽略这种情况:

def extract_flat_branch(nested_dict, c = []):
   for i in ['left', 'op', 'right', 'func', 'value', 'args', 'ctx', 'body', 'comparators', 'ops', 'test', 'orelse', 'targets', 'slice', 'n', 'id']:
      if i in nested_dict:
        if isinstance(nested_dict[i], list):
            for b in nested_dict[i]:
                yield from extract_flat_branch(b, c+[nested_dict['_type']]) 
        elif isinstance(nested_dict[i], dict): #simple check here
            yield from extract_flat_branch(nested_dict[i], c+[nested_dict['_type']]) 
        else:
            yield c+[nested_dict[i]]


print(list(extract_flat_branch(data)))

输出:

[['FunctionDef', 'Assign', 'Call', 'Name', 'Load'], ['FunctionDef', 'Assign', 'Call', 'Name', 'list'], ['FunctionDef', 'Assign', 'Call', 'Name', 'Load'], ['FunctionDef', 'Assign', 'Call', 'Name', 'items'], ['FunctionDef', 'Assign', 'Name', 'Store'], ['FunctionDef', 'Assign', 'Name', 'items'], ['FunctionDef', 'Assign', 'Call', 'Name', 'Load'], ['FunctionDef', 'Assign', 'Call', 'Name', 'next_power_of_two'], ['FunctionDef', 'Assign', 'Call', 'Call', 'Name', 'Load'], ['FunctionDef', 'Assign', 'Call', 'Call', 'Name', 'int'], ['FunctionDef', 'Assign', 'Call', 'Call', 'BinOp', 'Num', 1.2], ['FunctionDef', 'Assign', 'Call', 'Call', 'BinOp', 'Mult'], ['FunctionDef', 'Assign', 'Call', 'Call', 'BinOp', 'Call', 'Name', 'Load'], ['FunctionDef', 'Assign', 'Call', 'Call', 'BinOp', 'Call', 'Name', 'len'], ['FunctionDef', 'Assign', 'Call', 'Call', 'BinOp', 'Call', 'Name', 'Load'], ['FunctionDef', 'Assign', 'Call', 'Call', 'BinOp', 'Call', 'Name', 'items'], ['FunctionDef', 'Assign', 'Name', 'Store'], ['FunctionDef', 'Assign', 'Name', 'size'], ['FunctionDef', 'Assign', 'BinOp', 'List', 'Load'], ['FunctionDef', 'Assign', 'BinOp', 'Mult'], ['FunctionDef', 'Assign', 'BinOp', 'Name', 'Load'], ['FunctionDef', 'Assign', 'BinOp', 'Name', 'size'], ['FunctionDef', 'Assign', 'Name', 'Store'], ['FunctionDef', 'Assign', 'Name', 'table'], ['FunctionDef', 'For', 'Assign', 'BinOp', 'Call', 'Name', 'Load'], ['FunctionDef', 'For', 'Assign', 'BinOp', 'Call', 'Name', 'hash_function'], ['FunctionDef', 'For', 'Assign', 'BinOp', 'Call', 'Name', 'Load'], ['FunctionDef', 'For', 'Assign', 'BinOp', 'Call', 'Name', 'i'], ['FunctionDef', 'For', 'Assign', 'BinOp', 'Mod'], ['FunctionDef', 'For', 'Assign', 'BinOp', 'Name', 'Load'], ['FunctionDef', 'For', 'Assign', 'BinOp', 'Name', 'size'], ['FunctionDef', 'For', 'Assign', 'Name', 'Store'], ['FunctionDef', 'For', 'Assign', 'Name', 'h'], ['FunctionDef', 'For', 'Assign', 'Name', 'Store'], ['FunctionDef', 'For', 'Assign', 'Name', 's'], ['FunctionDef', 'For', 'While', 'AugAssign', 'Add'], ['FunctionDef', 'For', 'While', 'AugAssign', 'Num', 1], ['FunctionDef', 'For', 'While', 'Assign', 'BinOp', 'BinOp', 'Name', 'Load'], ['FunctionDef', 'For', 'While', 'Assign', 'BinOp', 'BinOp', 'Name', 'h'], ['FunctionDef', 'For', 'While', 'Assign', 'BinOp', 'BinOp', 'Add'], ['FunctionDef', 'For', 'While', 'Assign', 'BinOp', 'BinOp', 'Name', 'Load'], ['FunctionDef', 'For', 'While', 'Assign', 'BinOp', 'BinOp', 'Name', 's'], ['FunctionDef', 'For', 'While', 'Assign', 'BinOp', 'Mod'], ['FunctionDef', 'For', 'While', 'Assign', 'BinOp', 'Name', 'Load'], ['FunctionDef', 'For', 'While', 'Assign', 'BinOp', 'Name', 'size'], ['FunctionDef', 'For', 'While', 'Assign', 'Name', 'Store'], ['FunctionDef', 'For', 'While', 'Assign', 'Name', 'h'], ['FunctionDef', 'For', 'While', 'Compare', 'Subscript', 'Name', 'Load'], ['FunctionDef', 'For', 'While', 'Compare', 'Subscript', 'Name', 'table'], ['FunctionDef', 'For', 'While', 'Compare', 'Subscript', 'Load'], ['FunctionDef', 'For', 'While', 'Compare', 'Subscript', 'Index', 'Name', 'Load'], ['FunctionDef', 'For', 'While', 'Compare', 'Subscript', 'Index', 'Name', 'h'], ['FunctionDef', 'For', 'While', 'Compare', None], ['FunctionDef', 'For', 'While', 'Compare', 'IsNot'], ['FunctionDef', 'For', 'Assign', 'Name', 'Load'], ['FunctionDef', 'For', 'Assign', 'Name', 'i'], ['FunctionDef', 'For', 'Assign', 'Subscript', 'Name', 'Load'], ['FunctionDef', 'For', 'Assign', 'Subscript', 'Name', 'table'], ['FunctionDef', 'For', 'Assign', 'Subscript', 'Store'], ['FunctionDef', 'For', 'Assign', 'Subscript', 'Index', 'Name', 'Load'], ['FunctionDef', 'For', 'Assign', 'Subscript', 'Index', 'Name', 'h'], ['FunctionDef', 'Return', 'Name', 'Load'], ['FunctionDef', 'Return', 'Name', 'table']]

更新的解决方案:

def extract_flat_branch(nested_dict, c = []):
  targets = {'left', 'op', 'right', 'func', 'value', 'args', 'ctx', 'body', 'comparators', 'ops', 'test', 'orelse', 'targets', 'slice', 'n', 'id', 'slice', 'annotation', 'arg', 'elts', 's', '_type'}
  for a, b in nested_dict.items():
     if a in targets:
        if isinstance(b, dict):
           yield from extract_flat_branch(b, c+[a])
        elif isinstance(b, list):
           for i in b:
              yield from extract_flat_branch(i, c+[a])
        else:
            yield c+[b]

print(list(extract_flat_branch(data)))

输出:

[['FunctionDef'], ['args', 'arguments'], ['args', 'args', 'arg'], ['args', 'args', None], ['args', 'args', 'self'], ['body', 'Expr'], ['body', 'value', 'Str'], ['body', 'value', 'Like items(), but with all lowercase keys.'], ['body', 'Return'], ['body', 'value', 'GeneratorExp']]

【讨论】:

  • @JDo 很高兴为您提供帮助!
  • @JDo 如果你首先有一个None 然后是一个bool 而不是一个可迭代对象,你或许应该检查nested_dict[i] 是否是一个可迭代对象(但要注意字符串)。再说一次,鉴于这种情况更频繁地发生,也许您的代码逻辑(或您的输入,但不太可能)可能需要更彻底的检修。
  • @JDo 请看我最近的编辑。由于目标键似乎可以存储任何类型的值,我认为解决此问题的最佳方法是简单地检查 nested_dict[i] 是否是可迭代的。
  • @JDo 我不确定输出是否是您现在要查找的内容,但在这种情况下,我添加了一行 yield c+[nested_dict[i]] 以在目标键的值不是的情况下生成输出行一个可迭代的。请查看我最近的编辑。
  • @JDo没问题,我看看
猜你喜欢
  • 1970-01-01
  • 2015-01-14
  • 1970-01-01
  • 1970-01-01
  • 2021-12-16
  • 1970-01-01
  • 1970-01-01
  • 2019-10-23
  • 2018-02-10
相关资源
最近更新 更多