我有一个二维列表,如:
data = [[1,2,3], [2,3,4], [4,5,6]]
Run Code Online (Sandbox Code Playgroud)
我想像这样将它写入 JSON 文件:
{
'data':[
[1,2,3],
[2,3,4],
[4,5,6]
]
}
Run Code Online (Sandbox Code Playgroud)
我得到这个json.dumps(data, indent=4, sort_keys=True):
{
'data':[
[
1,
2,
3
],
[
2,
3,
4
],
[
4,
5,
6]
]
}
Run Code Online (Sandbox Code Playgroud)
这是另一个问题如何在使用 JSON 模块进行漂亮打印时实现自定义缩进?,但那是字典。
我以为您可以使用我对另一个类似问题的回答来做您想做的事。虽然它适用于json.dumps(),但您指出由于某种原因它不适用于json.dump()。
在调查此事后,我发现链接答案中被覆盖encode()的派生方法json.JSONEncoder仅在调用时dumps()调用,而在dump()调用时不调用。
幸运的是,我能够确定的iterencode()方法确实在这两种情况下被调用-所以是能够通过更多或更少的只是移动的代码来解决这个问题encode()到iterencode()。
下面的代码是修订版,其中包含以下更改:
我对其他问题的回答中代码的修改版本:
from _ctypes import PyObj_FromPtr # see /sf/answers/1050897011/
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
Run Code Online (Sandbox Code Playgroud)
将其应用于您的问题:
# 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).
Run Code Online (Sandbox Code Playgroud)
结果输出:
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
Run Code Online (Sandbox Code Playgroud)