【问题标题】:Write two-dimensional list to JSON file将二维列表写入 JSON 文件
【发布时间】:2017-07-31 08:31:31
【问题描述】:

我有一个二维列表,例如:

data = [[1,2,3], [2,3,4], [4,5,6]]

我想像这样将它写入 JSON 文件:

{
    'data':[
        [1,2,3],
        [2,3,4],
        [4,5,6]
    ]
}

我得到这个:json.dumps(data, indent=4, sort_keys=True):

{
    'data':[
        [
         1,
         2,
         3
        ],
        [
         2,
         3,
         4
        ],
        [
         4,
         5,
         6]
    ]
}

这是另一个问题How to implement custom indentation when pretty-printing with the JSON module?,但那是字典。

【问题讨论】:

  • 您似乎忘记在问题中包含问题。
  • 是的,我想要第一个样式。
  • 更新了我的答案。

标签: python json


【解决方案1】:

你只需要将它添加到一个空字典中:

data = [[1,2,3], [2,3,4], [4,5,6]]
a = {}
a.update({"data":data})
print a

#{'data': [[1, 2, 3], [2, 3, 4], [4, 5, 6]]}

您在第一种样式中尝试的只是 dict 格式。要从该字典中获取准确的 json 您可以将此字典添加到您的 json.dump 以转储文件。

对于 json 格式,您只需将其转储为:

import json
b = json.dumps(a)
print b
#{"data": [[1, 2, 3], [2, 3, 4], [4, 5, 6]]}

你可以去pro.jsonlint.com看看json格式是否正确。

【讨论】:

  • 是的,我只写了第二种风格,但我不能写第一种风格。
  • @LiZiming你可以去pro.jsonlint.com查看json格式是否正确。转储后查看字典和数据的内容
【解决方案2】:

我认为您可以使用my answer 回答另一个类似的问题来做您想做的事。虽然它适用于json.dumps(),但您指出由于某种原因它不适用于json.dump()

在调查此事后,我发现在链接答案中被覆盖的派生json.JSONEncoderencode() 方法仅在调用dumps() 时调用,而不是在调用dump() 时调用。

幸运的是,我能够确定iterencode() 方法确实 在这两种情况下都被调用了——因此能够通过或多或少简单地从encode() 移动代码来解决问题到iterencode()

下面的代码是一个修改过的版本:

修改后的版本的代码在我对其他问题的回答中:

from _ctypes import PyObj_FromPtr  # see https://stackoverflow.com/a/15012814/355230
import json
import re


class NoIndent(object):
    """ Value wrapper. """
    def __init__(self, value):
        if not isinstance(value, (list, tuple)):
            raise TypeError('Only lists and tuples can be wrapped')
        self.value = value


class MyEncoder(json.JSONEncoder):
    FORMAT_SPEC = '@@{}@@'  # Unique string pattern of NoIndent object ids.
    regex = re.compile(FORMAT_SPEC.format(r'(\d+)'))  # compile(r'@@(\d+)@@')

    def __init__(self, **kwargs):
        # Keyword arguments to ignore when encoding NoIndent wrapped values.
        ignore = {'cls', 'indent'}

        # Save copy of any keyword argument values needed for use here.
        self._kwargs = {k: v for k, v in kwargs.items() if k not in ignore}
        super(MyEncoder, self).__init__(**kwargs)

    def default(self, obj):
        return (self.FORMAT_SPEC.format(id(obj)) if isinstance(obj, NoIndent)
                    else super(MyEncoder, self).default(obj))

    def iterencode(self, obj, **kwargs):
        format_spec = self.FORMAT_SPEC  # Local var to expedite access.

        # Replace any marked-up NoIndent wrapped values in the JSON repr
        # with the json.dumps() of the corresponding wrapped Python object.
        for encoded in super(MyEncoder, self).iterencode(obj, **kwargs):
            match = self.regex.search(encoded)
            if match:
                id = int(match.group(1))
                no_indent = PyObj_FromPtr(id)
                json_repr = json.dumps(no_indent.value, **self._kwargs)
                # Replace the matched id string with json formatted representation
                # of the corresponding Python object.
                encoded = encoded.replace(
                            '"{}"'.format(format_spec.format(id)), json_repr)

            yield encoded

将其应用于您的问题:

# Example of using it to do get the results you want.

alfa = [('a','b','c'), ('d','e','f'), ('g','h','i')]
data = [(1,2,3), (2,3,4), (4,5,6)]

data_struct = {
    'data': [NoIndent(elem) for elem in data],
    'alfa': [NoIndent(elem) for elem in alfa],
}

print(json.dumps(data_struct, cls=MyEncoder, sort_keys=True, indent=4))

# Test custom JSONEncoder with json.dump()
with open('data_struct.json', 'w') as fp:
    json.dump(data_struct, fp, cls=MyEncoder, sort_keys=True, indent=4)
    fp.write('\n')  # Add a newline to very end (optional).

结果输出:

{
    "alfa": [
        ["a", "b", "c"],
        ["d", "e", "f"],
        ["g", "h", "i"]
    ],
    "data": [
        [1, 2, 3],
        [2, 3, 4],
        [4, 5, 6]
    ]
}

【讨论】:

  • 谢谢,为什么转储可以工作,但直接转储到文件效果不好?
  • 不确定您所说的“不太好”是什么意思。有时间会研究的。
  • 我的意思是把字典转成json并写入文件,打开文件,它看起来像上面显示的打印结果。当使用转储函数直接在文件中写入字典时,它显示为:@@memory id@@。 dunp 代码是:使用 io.open("test.json", "w") 作为 jsonfile。 json.dump(data, jsonfile, indent=4, cls=MyEncodes).
  • @LiZiming:我明白你的意思了。问题是,由于某种未知原因,MyEncoder.encode() 方法在调用json.dump() 时没有被调用,就像在使用json.dumps() 时一样。不知道为什么——尤其是考虑到这是我 4 年前写的一个答案。由于覆盖 encode() 是一种相当少见的做法,因此我可能需要一段时间才能进一步深入研究 - 但是,如果我找到解决方案,我会相应地更新我的答案。
  • @markroxor:确实,我的链接答案有类似的问题,我在过去七年的某个时候纠正了这个问题,但这些更新从未应用于这个本身已经有几年历史的问题——直到现在。感谢您指出问题。
猜你喜欢
  • 2012-12-14
  • 2018-03-08
  • 1970-01-01
  • 2020-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-04
相关资源
最近更新 更多