【问题标题】:Adding duplicate keys to JSON with python使用 python 向 JSON 添加重复键
【发布时间】:2015-06-13 17:14:44
【问题描述】:

有没有办法用 python 向 json 添加重复键?

据我了解,python 字典中不能有重复的键。通常,我创建 json 的方法是创建字典,然后创建 json.dumps。但是,出于测试目的,我需要 JSON 中的重复键。但我不能这样做,因为我不能在 python 字典中添加重复的键。我正在尝试在 python 3 中执行此操作

【问题讨论】:

  • @DonkeyKong 很遗憾没有...
  • 字典中不能有重复的键。 json 中不能有重复的键。
  • 在 JSON 文件格式中可以有重复的键。
  • JSON 中的重复键不可互操作,如 RFC 中所述:名称全部唯一的对象是可互操作的。但是,您可以在 Python 中编写自己的 JSON 编码器/解码器,以便将列表中具有多个值的 dict 折叠成多个 k:v 对
  • @taesu 你可以在 JSON 中有重复的键

标签: python json python-3.x


【解决方案1】:

你总是可以手动构造这样一个字符串值。

另一方面,可以使 CPython json 模块对重复键进行编码。这在 Python 2非常很棘手,因为 json 模块根本不尊重鸭子类型。

直接的解决方案是从 collections.Mapping 继承 - 你不能,因为 "MyMapping 不是 JSON 可序列化的。"

下一个尝试子类化dict - 好吧,但是如果json.dumps 注意到类型是dict,它会跳过调用__len__,并直接查看底层dict - 如果它是空的, {} 是直接输出的,所以很明显如果我们伪造方法,底层字典一定不能为空。

下一个快乐的源泉是实际上调用了__iter__,它迭代了键;对于每个键,__getitem__ 被调用,所以我们需要记住给定键返回的对应值是什么......因此我们得出了一个非常丑陋的 Python 2 解决方案:

class FakeDict(dict):
    def __init__(self, items):
        # need to have something in the dictionary
        self['something'] = 'something'
        self._items = items

    def __getitem__(self, key):
        return self.last_val

    def __iter__(self):
        def generator():
            for key, value in self._items:
                self.last_val = value
                yield key

        return generator()

在 CPython 3.3+ 中稍微容易一些...不,collections.abc.Mapping 不起作用,是的,您需要继承 dict,是的,您需要假装您的字典有内容...但是内部 JSON 编码器调用 items 而不是 __iter____getitem__

因此在 Python 3 上:

import json

class FakeDict(dict):
    def __init__(self, items):
        self['something'] = 'something'
        self._items = items
    def items(self):
        return self._items

print(json.dumps(FakeDict([('a', 1), ('a', 2)])))

打印出来

{"a": 1, "a": 2}

【讨论】:

  • 嗯,在我的解释器中运行这段代码,我得到'{}'
  • 咳咳,Python 3 版本忘记添加伪造的内容了
  • 它不工作。它只是打印 {'something':'something'}
  • @VennilaM 什么,在哪里?
  • 像魅力一样工作。它可以简单地使用obj = json.loads(data, object_pairs_hook=FakeDict) 然后json.dumps(obj)
【解决方案2】:

其实很简单:

$> python -c "import json; print json.dumps({1: 'a', '1': 'b'})"
{"1": "b", "1": "a"}

【讨论】:

    【解决方案3】:

    非常感谢 Antti Haapala,我发现您甚至可以使用它来将元组数组转换为 FakeDict:

    def function():
        array_of_tuples = []
        array_of_tuples.append(("key","value1"))
        array_of_tuples.append(("key","value2"))
        return FakeDict(array_of_tuples)
    
    print(json.dumps(function()))
    

    输出:

    {"key": "value1", "key": "value2"}
    

    如果您将 FakeDict 类更改为此空字典将被正确解析:

    class FakeDict(dict):
        def __init__(self, items):
            if items != []:
                self['something'] = 'something'
            self._items = items
        def items(self):
            return self._items
    def test():
        array_of_tuples = []
        return FakeDict(array_of_tuples)
    
    print(json.dumps(test()))
    

    输出:

    "{}"
    

    【讨论】:

      猜你喜欢
      • 2019-06-08
      • 2019-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多