Как изменить этот код, чтобы удалить глобальную переменную? (распаковка вложенного рекурсивного генератора json) - PullRequest
1 голос
/ 04 мая 2019

У меня есть json, который я хотел бы распаковать в pandas dataframe, я могу сделать это, используя следующий код. Есть ли способ изменить код для удаления глобальной переменной?

d = {
        "name":"Vertebrates",
        "children":[
        {
            "name":"Mammals",
            "children":[
            {
                "name":"human"
            },
            {
                "name":"chimpanzee"
            }
            ]
        },
        {
            "name":"Birds",
            "children":[
            {
                "name":"chicken"
            },
            {
                "name":"turkey"
            }
            ]
        }
        ]
    }

path = []

def unpack(d):
    global path
    if len(d) == 1:
        yield(d['name'], path)
    else:
        path.append(d['name'])
        for item in d['children']:
            yield from unpack(item)
        path = path[:-1]

pd.DataFrame.from_dict({key:value for key, value in unpack(d)},orient='index')

EDIT:

Я фактически начал с пути в качестве аргумента ключевого слова, проблема заключалась в том, что я получил это:

(«человек», [«позвоночные», «млекопитающие»])
(«шимпанзе», [«позвоночные», «млекопитающие»])
(«курица», [«позвоночные», «млекопитающие», «птицы»])
(«индейка», [«позвоночные», «млекопитающие», «птицы»])

где для курицы и индейки путь еще имеет слово млекопитающие, потому что строка: "путь = путь [: - 1]" была бесполезна в этом коде. поэтому я решил использовать глобальную переменную, чтобы удостовериться, что удаляю последний элемент всякий раз, когда ветвь в рекурсии заканчивается.

РЕШИТЬ: Ответ blhsing может решить проблему, удалив функцию добавления. Ответ bigwillydos также помогает.

Я не знал, что в рекурсиях обновления переменных эффективны в прямом направлении, но неэффективны в обратном направлении. вот почему я получал накопленный путь для более поздних имен.

Ответы [ 3 ]

3 голосов
/ 04 мая 2019

Сделать path необязательным аргументом.По умолчанию это пустой список в начальном вызове, но вы передаете его явно в рекурсивных вызовах.

def unpack(d, path = None):
    if path is None:
        path = []
    if len(d) == 1:
        yield(d['name'], path)
    else:
        path.append(d['name'])
        for item in d['children']:
            yield from unpack(item, path)
        path = path[:-1]

Не делайте ошибку, помещая значение по умолчанию в список параметров;не пишите:

def unpack(d, path = []):

См. "Наименьшее изумление" и изменяемый аргумент по умолчанию для объяснения.

1 голос
/ 04 мая 2019

Вместо этого вы можете сделать path вторым параметром со значением по умолчанию пустого кортежа. Вам также не нужно добавлять элемент перед вызовом только для удаления элемента после вызова. Стек вызовов рекурсивного вызова сделает это за вас:

def unpack(d, path=()):
    if len(d) == 1:
        yield(d['name'], path)
    else:
        for item in d['children']:
            yield from unpack(item, path + (d['name'],))
0 голосов
/ 04 мая 2019

Сделать path статической переменной для функции unpack

import pandas as pd

def static_vars(**kwargs):
    def decorate(func):
        for k in kwargs:
            setattr(func, k, kwargs[k])
        return func
    return decorate

@static_vars(path=[])
def unpack(d):
    if len(d) == 1:
        yield(d['name'], unpack.path)
    else:
        unpack.path.append(d['name'])
        for item in d['children']:
            yield from unpack(item)
        unpack.path = unpack.path[:-1]

def main():
    d = {
        "name":"Vertebrates",
        "children":[
        {
            "name":"Mammals",
            "children":[
            {
                "name":"human"
            },
            {
                "name":"chimpanzee"
            }
            ]
        },
        {
            "name":"Birds",
            "children":[
            {
                "name":"chicken"
            },
            {
                "name":"turkey"
            }
            ]
        }
        ]
    }

    df = pd.DataFrame.from_dict({key:value for key, value in unpack(d)},orient='index')

    print(df)

if __name__ == '__main__':
    main()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...