首页 > 解决方案 > json.dumps 和 json.loads 在任何字符串的列表上运行是否安全?

问题描述

在 Python 中对文本列表进行 JSON 序列化/反序列化时丢失信息是否有危险?

给定一个字符串列表lst

lst = ['str1', 'str2', 'str3', ...]

如果我跑

lst2 = json.loads(json.dumps(lst))

总是会lst完全一样lst2(即lst == lst2总是会导致True)?或者是否有一些特殊的、不寻常的字符会破坏这些方法中的任何一种?

我很好奇,因为我将处理来自各种 Unicode 范围的许多不同和不寻常的字符,我想绝对确定这个过程是 100% 健壮的。

标签: pythonjson

解决方案


取决于您所说的“完全相同”。我们可以确定三个不同的问题:

  • 语义身份。您读入的内容与您写回的内容在含义上是等价的,只要它首先是明确定义的。Python(取决于版本)可能会重新排序字典键,并且对于某些代码点通常更喜欢 Unicode 转义而不是文字字符,反之亦然。

    >>> json.loads(json.dumps("\u0050\U0001fea5\U0001f4a9"))
    'P\U0001fea5'
    
  • 词汇身份。没有。如上所示,Unicode 代码点的 JSON 表示可以以不同的方式进行规范化,从而\u0050变成文字P,可打印的表情符号可能会或可能不会类似地变成 Unicode 转义,反之亦然。

    (这与正确的Unicode 规范化不同,后者确保同形文字变成相同的精确代码点。)

  • 垃圾进,同样的垃圾出。没有。如果您有无效的输入,Python 通常会崩溃而不是通过它,尽管您可以通过捕获错误和/或传递标志来修改其中的一些以请求不那么严格的行为。

    >>> json.loads(r'"\u123"')
      File "<stdin>", line 1
    SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 0-4: truncated \uXXXX escape
    
    >>> print(json.loads(r'"\udcff"'))
    ?
    >>> #!? should probably crash or moan instead!
    

您似乎在询问第一种情况,但如果您不确定如何处理无效的 Unicode 数据,第三种情况可能会严重影响您。

如果您关心磁盘上的 JSON 在版本之间是等效的,则第二种情况会有所不同;这对你来说似乎并不重要,但这个问题的未来访问者可能会很在意。


推荐阅读