Supposons que j'ai une liste imbriquée arbitrairement dans laquelle certains des éléments imbriqués peuvent être des générateurs. Par exemple:
[ [1, [2, [3, 4]]], [2, [1, 2, 3]], [3, [['0'], ['0', '1']]], {'a': [{'x': [0.0, 1.0]}, {'y': [0.0, 1.0]}, {'z': [0.0, 1.0]}]}, {'b': {'c': {0: 'a', 1: 'b', 2: 'c'}}} ]
Comment puis-je parcourir cette structure de manière récursive et consommer tous les objets générateurs afin qu'ils puissent être picklés?
Ma sortie souhaitée est: p >
nested_gens = [ [1, [2, [3, 4]]], [2, (map(int, '123'))], [3, (map(str, range(i+1)) for i in range(2))], {'a': ({k: (float(i) for i in range(2))} for k in 'xyz')}, {'b': {'c': dict(zip(range(3), 'abc'))}} ]
Une solution à cette question pourrait être généralisée pour le décapage des objets contenant des générateurs. Toutes les réponses que j'ai trouvées pour traiter TypeError: impossible de décaper les objets du générateur
ne concernent pas les générateurs imbriqués.
Mise à jour : La solution doit être capable de gérer des éléments imbriqués de tout type.
3 Réponses :
Une façon est de parcourir l'objet imbriqué de manière récursive et de transformer les générateurs en listes
s.
print(consume_all_generators(nested_gens)) #[[1, [2, [3, 4]]], # [2, [1, 2, 3]], # [3, [['0'], ['0', '1']]], # {'a': [{'x': [0.0, 1.0]}, {'y': [0.0, 1.0]}, {'z': [0.0, 1.0]}]}, # {'b': {'c': {0: 'a', 1: 'b', 2: 'c'}}}]
Appliquer ceci à l'exemple de la question:
from inspect import isgenerator, isgeneratorfunction def consume_all_generators(row): if isinstance(row, str): return row elif isinstance(row, dict): return {k: consume_all_generators(v) for k, v in row.items()} output = [] try: for val in row: if isgenerator(val) or isgeneratorfunction(val): output.append(list(consume_all_generators(val))) else: output.append(consume_all_generators(val)) return output except TypeError: return row
Vous pouvez également utiliser une compréhension de liste en récursivité pour une solution sans importation:
[[1, [2, [3, 4]]], [2, [1, 2, 3]], [3, [['0'], ['0', '1']]], {'a': [{'x': [0.0, 1.0]}, {'y': [0.0, 1.0]}, {'z': [0.0, 1.0]}]}, {'b': {'c': {0: 'a', 1: 'b', 2: 'c'}}}]
nested_gens = [ [1, [2, [3, 4]]], [2, (map(int, '123'))], [3, (map(str, range(i+1)) for i in range(2))], {'a': ({k: (float(i) for i in range(2))} for k in 'xyz')}, {'b': {'c': dict(zip(range(3), 'abc'))}} ] print(_test(nested_gens))
Résultat:
def _test(d): if isinstance(d, str): return d try: _l = [i for i in d] return [_test(i) for i in _l] if not isinstance(d, dict) else {a:_test(b) for a, b in d.items()} except: return d
Essayez ceci
def consume(g): if hasattr(g, '__iter__') and not isinstance(g, str): if isinstance(g, tuple): return (consume(e) for e in g) elif isinstance(g, dict): return { k: consume(v) for k,v in g.items()} else: return [consume(e) for e in g] return g nested_gens = [ [1, [2, [3, 4]]], [2, (map(int, '123'))], [3, (map(str, range(i+1)) for i in range(2))], {'a': ({k: (float(i) for i in range(2))} for k in 'xyz')}, {'b': {'c': dict(zip(range(3), 'abc'))}} ] print(consume(nested_gens))