Представьте, у меня есть диктофон {"a": "hello", "b": b"list"}
Я хотел бы сериализовать 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"
Вы имеете в виду {'a': 'hello', 'b': 'list'}
?
Пожалуйста, отредактируйте вопрос, чтобы уточнить, что вы хотите. "b": list
недействителен JSON, и совершенно неясно, как вставка кода <:<:
:>:>
для удаления необходимых кавычек связана с вашей целью создания JSON.
@ДжамиуС. нет... у меня есть ключ, который содержит байт... я хотел бы сериализовать в строку...
Ваш желаемый результат это? {"a": "hello", "b": "list"}
?
@no_hex .. нет, я действительно хочу '{"a": "hello", "b": list}'
(что на самом деле не json!)
Вы хотите, чтобы значение было фактическим типом list
? так что вы можете вызвать dictionary['b']((1,2,3))
?
@no_hex ... не "список" - произвольное слово ... на самом деле, я хотел бы, чтобы каждая строка байтов сериализовалась в строку, но без кавычек (например: b'mymethod' -> mymethod, а не "мой метод")
Чтобы добиться желаемого результата, то есть '{"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 Извините, я хотел написать «ваше решение работает», но не будет работать, если значения содержат <:<:
, который является «протоколом», который вы создали для себя, возможно, значения никогда не будут содержать этот набор символов :-)
@manatlan Моя функция не будет знать, как обращаться с объектами, кроме словарей, хотя это не было указано в вашем первоначальном вопросе. Желаемый вами метод гораздо более надежен и не относится к словарю или списку, я думаю, что это должно быть в другом вопросе.
вы правы.... но не хочу засорять ТАК своими тупыми вопросами... вот и отредактировал, чтобы было понятнее
@manatlan А как насчет сложных объектов? например [a, b"b", {"c": b"list"}]
(список, содержащий словарь)
ты бог... я пытался написать что-то подобное, но ты был быстрее. ...
Я думал, что есть более простой способ python/json решить эту проблему... но нет, вам нужно будет протестировать каждый тип и отобразить каждый тип... поэтому я считаю, что мое решение (самое короткое и простое) должно быть сохранено ;-( большое спасибо
@manatlan Спасибо за комплименты :) всегда пожалуйста!
Ваш желаемый результат недействителен json...