Python高效反向列表JSON序列化

Python高效反向列表JSON序列化,python,json,Python,Json,我在寻找一种高效的方法,以相反的顺序序列化python列表 我试图做json.dumps(反向(mylist)),但显然json.dumps不接受迭代器 我也可以做json.dumps(list(reversed(mylist)),但是对于非常大的列表,这是非常低效的,我不需要创建临时列表,我希望动态序列化列表,而不是创建临时列表 我想我可以使用json.jsonecoder来实现这一点,但我并没有真正从default函数中得到应该返回的内容 我还必须坚持使用标准库,因为我没有安装其他软件包的自

我在寻找一种高效的方法,以相反的顺序序列化python列表

我试图做
json.dumps(反向(mylist))
,但显然
json.dumps
不接受迭代器

我也可以做
json.dumps(list(reversed(mylist))
,但是对于非常大的列表,这是非常低效的,我不需要创建临时列表,我希望动态序列化列表,而不是创建临时列表

我想我可以使用
json.jsonecoder
来实现这一点,但我并没有真正从
default
函数中得到应该返回的内容

我还必须坚持使用标准库,因为我没有安装其他软件包的自由

到目前为止,我尝试了两种建议的解决方案,以下是测试结果:

>>> timeit.timeit('li.reverse(); json.dumps(li)', number=1, globals=globals())
2.5034537549945526
>>> timeit.timeit('"[{}]".format(",".join(map(json.dumps,reversed(li))))', number=1, globals=globals())
41.076039729989134

我仍然认为实现我自己的
jsonecoder
会更有效,但我仍然不知道如何做到这一点。

避免复制的一种方法是将列表倒过来,例如:

mylist.reverse()
json_string = json.dumps(mylist)

然后
mylist.reverse()
如果需要,请将其返回。

在我们发疯之前,请查看以下各项是否满足您的性能要求:

mylist.reverse(); json.dumps(mylist); mylist.reverse()
json.dumps(mylist[::-1])
json.dumps(tuple(reversed(mylist)))
您提到定义自己的JSONEncoder默认函数,这相当简单(最下面的示例*),但我认为它在这里不起作用,因为json.JSONEncoder需要默认函数将对象转换为以下内容之一:

None, True, False, str, int, float, list, tuple, dict
将迭代器转换为列表或元组将创建一个大型对象,这正是我们试图避免的

您需要修改json库或对其进行修补

以下是json.encoder的CPython源代码。PyPy、Jython和其他Python实现可能对json模块使用相同的代码

出于性能原因,您需要在函数外部定义迭代器类型,并将其作为本地类型引入

str_iterator   = type(iter( str()    ))
list_iterator  = type(iter( list()   ))
tuple_iterator = type(iter( tuple()  ))
range_iterator = type(iter( range(0) ))
list_reverseiterator = type(reversed( list()  )) 
reverseiterator      = type(reversed( tuple() )) #same as <class 'reversed'>

# Add any other iterator classes that you need here, plus any container data types that json doesn't support (sets, frozensets, bytes, bytearray, array.array, numpy.array)
iterator_types = (str_iterator, list_iterator, tuple_iterator, range_iterator,
                  list_reverseiterator, reversed)
这些更改如下所示:

*正如所承诺的那样,如何定义自己的默认函数,尽管对于在不将迭代器复制到列表或元组的情况下转储迭代器来说并不有用

class JSONEncoderThatSupportsIterators(json.JSONEncoder):
    def default(self, o):
        try:
            iterable = iter(o)
        except TypeError:
            pass
        else:
            return list(iterable)
        # Let the base class default method raise the TypeError
        return json.JSONEncoder.default(self, o)

li = range(10000000) # or xrange if Python 2
dumped = JSONEncoderThatSupportsIterators().encode(reversed(li))
assert dumped.startswith('[999999, 999998, 999997, ')
assert dumped.endswith('6, 5, 4, 3, 2, 1, 0]')

或者,您可以定义
default(self,o)
函数并将其作为参数传递给
json,而不是子类化
json.jsonecoder
,dumps(default=default)

已就位,首先使用
mylist.reverse()
(避免复制)反转列表-执行序列化,然后,如果需要的话,再次将其反转?这比创建一个新列表要好,但它仍然会创建一个不需要的中间步骤。但谢谢你的提示。:)浏览了json库之后——它并不像看上去那么简单。默认的JSONDecoder.default有一点说,例如,为了支持任意迭代器,您可以。。。但这意味着您将从该iterable返回一个列表,该列表对于子iterable是有意义的(例如,如果您有
{test:range(10)}
扩展了…但不是对整个
数据进行反向
。更为复杂的是,一些级别由C实现处理,而其他位则由
\u函数
和嵌套的
\u函数
…为了简单起见,我坚持使用
列表。反向
json.dumps(mylist[:-1])
是另一种方法,但重复列表。
import json
def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
        _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot,
         iterable_types=_get_iterable_types(),
         ...
    ):
    ...

json.encoder._make_iterencode = _make_iterencode
class JSONEncoderThatSupportsIterators(json.JSONEncoder):
    def default(self, o):
        try:
            iterable = iter(o)
        except TypeError:
            pass
        else:
            return list(iterable)
        # Let the base class default method raise the TypeError
        return json.JSONEncoder.default(self, o)

li = range(10000000) # or xrange if Python 2
dumped = JSONEncoderThatSupportsIterators().encode(reversed(li))
assert dumped.startswith('[999999, 999998, 999997, ')
assert dumped.endswith('6, 5, 4, 3, 2, 1, 0]')