Изменить поведение json.dumps: настроить сериализацию

Представьте, у меня есть диктофон {"a": "hello", "b": b"list"}

  • 'а' это строка
  • 'b' - это строка байтов

Я хотел бы сериализовать dict в строку «json» (*) -> '{"a": "hello", "b": list}'

(*): не совсем совместим с json

Для этого я написал этот метод, он работает ....

def stringify(obj):
    def my(obj):
        if isinstance(obj,bytes):
            return "<:<:%s:>:>" % obj.decode()
    return json.dumps(obj, default=my).replace('"<:<:',"").replace(':>:>"',"")

(«<:<:» и «:>:>» просто добавляются перед сериализацией, чтобы быть замененными, после сериализации json, для получения желаемого результата)

Это немного хакерски, используя подстановку строк для получения результата... это работает ;-)

Я спрашиваю себя и вас, можно ли это сделать лучше/питонов... Есть ли у вас какие-либо идеи ?

РЕДАКТИРОВАТЬ Я хотел бы лучше переписать свою строку с утверждениями:

assert stringify( dict(a = "hello",b=b"byte") ) == '{"a": "hello", "b": byte}'
assert stringify( ["hello", b"world"] ) == '["hello", world]'
assert stringify( "hello" ) == '"hello"'
assert stringify( b"world" ) == "world"

Ваш желаемый результат недействителен json...

derpirscher 03.02.2023 14:15

Вы имеете в виду {'a': 'hello', 'b': 'list'}?

Jamiu S. 03.02.2023 14:22

Пожалуйста, отредактируйте вопрос, чтобы уточнить, что вы хотите. "b": list недействителен JSON, и совершенно неясно, как вставка кода <:<::>:> для удаления необходимых кавычек связана с вашей целью создания JSON.

MisterMiyagi 03.02.2023 14:28

@ДжамиуС. нет... у меня есть ключ, который содержит байт... я хотел бы сериализовать в строку...

manatlan 03.02.2023 14:37

Ваш желаемый результат это? {"a": "hello", "b": "list"} ?

CodeCop 03.02.2023 14:38

@no_hex .. нет, я действительно хочу '{"a": "hello", "b": list}' (что на самом деле не json!)

manatlan 03.02.2023 14:40

Вы хотите, чтобы значение было фактическим типом list? так что вы можете вызвать dictionary['b']((1,2,3))?

CodeCop 03.02.2023 14:44

@no_hex ... не "список" - произвольное слово ... на самом деле, я хотел бы, чтобы каждая строка байтов сериализовалась в строку, но без кавычек (например: b'mymethod' -> mymethod, а не "мой метод")

manatlan 03.02.2023 14:48
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
8
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Чтобы добиться желаемого результата, то есть '{"a": "hello", "b": list}', вам нужно будет сделать несколько уродливых, но справедливых косметических изменений, например, самостоятельно восстановить словарь. Поскольку старый добрый словарь {"a": "hello", "b": list} не имеет смысла как переменная Python (ну, этот конкретный пример имеет смысл, только потому, что мы используем встроенный list, но если бы это был «mymethod» или что-то еще — это не было бы)

def stringify(input_dict: dict):
    for k, v in input_dict.items():
        if isinstance(v, bytes):
            input_dict[k] = v.decode()
        else:
            input_dict[k] = f'"{v}"'
    return '{' + ', '.join([f'{k}: {v}' for k, v in input_dict.items()]) + '}'

Мы видим, что здесь мы буквально восстанавливаем словарь, используя символы ASCII, не так уж плохо, не так интуитивно, но, тем не менее, работает так, как задумано. Ваше решение работает, но оно не будет работать, если одно из значений в словаре имеет этот специальный набор символов <:<:.


Делаем этот код:

d = {"a": "hello", "b": b"list"}
serialized_dict = stringify(d)
print(serialized_dict)

Выход:

{a: "hello", b: list}

Который имеет тип str, НЕ допустимый JSON.


Редактировать — более общая функция stringify.

Мы можем сделать это умнее, рекурсивно вызывая функцию stringify, и если мы встречаем атомарный объект (например, int, str и т. д.), мы возвращаем его в кавычках, иначе (например, bytes) мы возвращаем его без кавычек.

def generic_stringify(input_generic_object):
    if isinstance(input_generic_object, dict):
        <paste the stringify function Ive posted above>

    elif isinstance(input_generic_object, list):
        return '[' + ', '.join([generic_stringify(v) for v in input_generic_object]) + ']'

    elif isinstance(input_generic_object, bytes):
        return input_generic_object.decode()
    
    else:
        return f'"{input_generic_object}"'

Здесь мы возвращаем декодированные байты, если тип bytes, и возвращаем их с кавычками, если тип str:

print(generic_stringify(dict(a = "hello", b=b"byte")))
print(generic_stringify(["hello", b"world", {"c": b"list"}]))
print(generic_stringify("hello"))
print(generic_stringify(b"world"))

Выходы:

{"a": "hello", "b": byte}
["hello", world, {"c": list}]
"hello"
world

Мое решение работает (кроме случаев, когда значение содержит "<:<:") и работает для всех типов (мой stringify может есть любые объекты (dict, list...)... но вы правы, мне нужно переопределить сериализацию dict по умолчанию!

manatlan 03.02.2023 15:03

@manatlan Извините, я хотел написать «ваше решение работает», но не будет работать, если значения содержат <:<:, который является «протоколом», который вы создали для себя, возможно, значения никогда не будут содержать этот набор символов :-)

CodeCop 03.02.2023 15:04

@manatlan Моя функция не будет знать, как обращаться с объектами, кроме словарей, хотя это не было указано в вашем первоначальном вопросе. Желаемый вами метод гораздо более надежен и не относится к словарю или списку, я думаю, что это должно быть в другом вопросе.

CodeCop 03.02.2023 15:16

вы правы.... но не хочу засорять ТАК своими тупыми вопросами... вот и отредактировал, чтобы было понятнее

manatlan 03.02.2023 15:18

@manatlan А как насчет сложных объектов? например [a, b"b", {"c": b"list"}] (список, содержащий словарь)

CodeCop 03.02.2023 15:22

ты бог... я пытался написать что-то подобное, но ты был быстрее. ...

manatlan 03.02.2023 15:37

Я думал, что есть более простой способ python/json решить эту проблему... но нет, вам нужно будет протестировать каждый тип и отобразить каждый тип... поэтому я считаю, что мое решение (самое короткое и простое) должно быть сохранено ;-( большое спасибо

manatlan 03.02.2023 15:40

@manatlan Спасибо за комплименты :) всегда пожалуйста!

CodeCop 03.02.2023 15:40

Другие вопросы по теме