Потреблять вложенные генераторы - PullRequest
0 голосов
/ 27 февраля 2019

Предположим, у меня есть произвольно вложенный список, в котором некоторые из вложенных элементов могут быть генераторами.Например:

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'))}}
]

Как я могу рекурсивно пройти через эту структуру и поглотить все объекты генератора?

Мой желаемый вывод:

[
    [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'}}}
]

Решение этого вопроса может быть обобщено для травления объектов, которые содержат генераторы.Все ответы, которые я нашел для работы с TypeError: can't pickle generator objects, не касаются вложенных генераторов.

Обновление : решение должно иметь возможность обрабатывать вложенные элементы любого типа.

Ответы [ 2 ]

0 голосов
/ 27 февраля 2019

Вы также можете использовать понимание списка в рекурсии для решения без импорта:

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

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))

Вывод:

[[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'}}}]
0 голосов
/ 27 февраля 2019

Один из способов - рекурсивно пройти через вложенный объект и превратить генераторы в list s.

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

Применение этого к примеру в вопросе:

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'}}}]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...