Гибридные данные с плоским многоуровневым вложенным списком словарей Yield

Python

В предыдущей статье мы говорили о том, как использовать PythonyieldКлючевое слово упрощает код, выравнивая многоуровневые вложенные словари.

А что, если наши данные — это не только словарь, но и список, представляющий собой многоуровневые вложенные данные словарного списка? Например:

nest_dict = {
    'a': 1,
    'b': {
        'c': 2,
        'd': 3,
        'e': {'f': 4}
    },
    'g': {'h': 5},
    'i': 6,
    'j': {'k': {'l': {'m': 8}}},
    'n': [1, {'o': 1, 'p': [1, 2, 3],  'q': {'r': {'s': 100}}}, 3, [1, 2, 3], 5]
}

Теперь остановитесь, наберите код и подумайте, как добавить логику для обработки списков.

Во-первых, давайте посмотрим, как выглядят данные после окончательного сглаживания:

{'a': 1,
 'b_c': 2,
 'b_d': 3,
 'b_e_f': 4,
 'g_h': 5,
 'i': 6,
 'j_k_l_m': 8,
 'n_0': 1,
 'n_1_o': 1,
 'n_1_p_0': 1,
 'n_1_p_1': 2,
 'n_1_p_2': 3,
 'n_1_q_r_s': 100,
 'n_2': 3,
 'n_3_0': 1,
 'n_3_1': 2,
 'n_3_2': 3,
 'n_4': 5}

для'n': ['a', 'b', 'c']С данными в этой форме мы преобразуем их в:{'n_0': 'a', 'n_1': 'b', 'n_2': 'c'}

Наш исходный основной код выглядит следующим образом:

def flat(x):
    for key, value in x.items():
        if isinstance(value, dict):
            for k, v in flat(value):
                k = f'{key}_{k}'
                yield (k, v)
        else:
            yield (key, value)

Ваша первая реакция — изменить код следующим образом:

def flat(x):
    for key, value in x.items():
        if isinstance(value, dict):
            for k, v in flat(value):
                k = f'{key}_{k}'
                yield (k, v)
        elif isinstance(value, list):
            "一大堆处理列表的代码"
        else:
            yield (key, value)

если вы используетеreturnи рекурсия, вам, вероятно, нужно написать так.

но если вы используетеyieldключевое слово, то, хотя вы должны изменить код, но модификация не здесь. Место, которое мы хотим изменить, этоfor key, value in x.items().

потому что.items()Этот метод является методом словаря, список не имеет этого метода. Итак, нам нужно написать универсальный итеративный генератор, поддерживающий словари и списки, поэтому мы добавляем функцию:iter_x:

def iter_x(x):
    if isinstance(x, dict):
        for key, value in x.items():
            yield (key, value)
    elif isinstance(x, list):
        for index, value in enumerate(x):
            yield (index, value)

Теперь мы вызываем эту новую функцию генератора в исходном коде:

def flat(x):
    for key, value in iter_x(x):
        if isinstance(value, (dict, list)):
            for k, v in flat(value):
                k = f'{key}_{k}'
                yield (k, v)
        else:
            yield (key, value)

в,isinstance(value, (dict, list)), эквивалентноisinstance(value, dict) or isinstance(value, list).

Давайте посмотрим на беговой эффект:

владелецyieldКлючевые слова, ваше мышление в области программирования и то, как вы думаете о проблемах, претерпят серьезные изменения.