Python: конвертировать типы в глубоко вложенный словарь или массив - PullRequest
1 голос
/ 06 января 2020

Я написал следующую вспомогательную функцию для преобразования ObjectIds (тип bson) в строки. Функция должна работать для глубоко вложенных словарей, массивов и их комбинаций.

Текущая функция указана ниже:

from datetime import datetime
from bson import ObjectId

def clean_dict_helper(d):
    if not d:
        return None
    if isinstance(d, list):  # For those db functions which return list
        if len(d) == 0:
            return []
        return [clean_dict_helper(x) for x in d]
    for k, v in d.items():
        if isinstance(v, dict):
            v = clean_dict_helper(v)
            d.update({k: v})
        else:
            if isinstance(v, ObjectId):
                v = str(v)
            elif isinstance(v, datetime):
                v = str(v)
            d.update({k: v})
    return d


test_case = {'id': bson.ObjectId("5e126ddf276ab18820e00ddf"), 'arr': [{'value': 4, 'id': bson.ObjectId("5e126ddf276ab18820e00ddf")}]}

result = clean_dict_helper(test_case)

print(result)
>>> {'arr': [{'id': ObjectId('5e126ddf276ab18820e00ddf'), 'value': 4}], 'id': '5e126ddf276ab18820e00ddf'}

Однако, похоже, она не работает для объектов внутри массивов внутри Объекты. Мне интересно, есть ли лучший способ перебирать вложенные итерации и конвертировать типы?

1 Ответ

2 голосов
/ 06 января 2020

Думаю, об этом будет легче подумать, если вы положите преобразование в начало, разрешите рекурсивным вызовам проходить ObjectId и вернуть преобразованные строки напрямую с помощью функции, а не пытаться преобразовать внутри циклов в функция. Затем вы можете просто передать значение в рекурсию и получить строку обратно.

Что-то вроде:

from datetime import datetime

def clean_dict_helper(d):
    if isinstance(d, ObjectId) or isinstance(d, datetime):
        return str(d)

    if isinstance(d, list):  # For those db functions which return list
        return [clean_dict_helper(x) for x in d]

    if isinstance(d, dict):
        for k, v in d.items():
            d.update({k: clean_dict_helper(v)})

    # return anything else, like a string or number
    return d

Вызов:

clean_dict_helper({
    1: {
        1: ObjectId('5e0e83a6d0fbe7238c960ea0'),
        2: [ObjectId('5e0e83a6d0fbe7238c960ea0'), ObjectId('5e0e83a6d0fbe7238c960ea0')],
        3: datetime(2020, 1, 1),
        4: [{1: ObjectId('5e0e83a6d0fbe7238c960ea0')}],
        5: 'test'
    },
    2: [ObjectId('5e0e83a6d0fbe7238c960ea0'), ObjectId('5e0e83a6d0fbe7238c960ea0')]
})

Затем вернет:

{1: {1: '5e0e83a6d0fbe7238c960ea0',
  2: ['5e0e83a6d0fbe7238c960ea0', '5e0e83a6d0fbe7238c960ea0'],
  3: '2020-01-01 00:00:00',
  4: [{1: '5e0e83a6d0fbe7238c960ea0'}],
  5: 'test'},
 2: ['5e0e83a6d0fbe7238c960ea0', '5e0e83a6d0fbe7238c960ea0']}

Кроме того, поскольку вы создаете новый список с пониманием, может иметь смысл возвращать новый dict, а не мутировать переданное значение с чем-то вроде:

    if isinstance(d, dict):
        return {k:clean_dict_helper(v) for k, v in d.items() }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...