<p>一个完整的简单易读的解决方案,它可以将生成器从普通的或空的iterable序列化,可以与.encode()或.iterencode()一起使用。笔试。使用Python2.7、3.0、3.3、3.6进行测试</p>
<pre><code>import itertools
class SerializableGenerator(list):
"""Generator that is serializable by JSON
It is useful for serializing huge data by JSON
>>> json.dumps(SerializableGenerator(iter([1, 2])))
"[1, 2]"
>>> json.dumps(SerializableGenerator(iter([])))
"[]"
It can be used in a generator of json chunks used e.g. for a stream
>>> iter_json = ison.JSONEncoder().iterencode(SerializableGenerator(iter([])))
>>> tuple(iter_json)
('[1', ']')
# >>> for chunk in iter_json:
# ... stream.write(chunk)
# >>> SerializableGenerator((x for x in range(3)))
# [<generator object <genexpr> at 0x7f858b5180f8>]
"""
def __init__(self, iterable):
tmp_body = iter(iterable)
try:
self._head = iter([next(tmp_body)])
self.append(tmp_body)
except StopIteration:
self._head = []
def __iter__(self):
return itertools.chain(self._head, *self[:1])
# -- test --
import unittest
import json
class Test(unittest.TestCase):
def combined_dump_assert(self, iterable, expect):
self.assertEqual(json.dumps(SerializableGenerator(iter(iterable))), expect)
def combined_iterencode_assert(self, iterable, expect):
encoder = json.JSONEncoder().iterencode
self.assertEqual(tuple(encoder(SerializableGenerator(iter(iterable)))), expect)
def test_dump_data(self):
self.combined_dump_assert(iter([1, "a"]), '[1, "a"]')
def test_dump_empty(self):
self.combined_dump_assert(iter([]), '[]')
def test_iterencode_data(self):
self.combined_iterencode_assert(iter([1, "a"]), ('[1', ', "a"', ']'))
def test_iterencode_empty(self):
self.combined_iterencode_assert(iter([]), ('[]',))
def test_that_all_data_are_consumed(self):
gen = SerializableGenerator(iter([1, 2]))
list(gen)
self.assertEqual(list(gen), [])
</code></pre>
<p>使用的解决方案:Vadim Pushtaev(不完整)、user1158559(不必要的复杂)和<a href="https://stackoverflow.com/a/45482776/448474">Claude</a>(在另一个问题中,也很复杂)。</p>
<p>有用的简化是:</p>
<ul>
<li>不必惰性地计算第一个项,它可以在<code>__init__</code>中完成,因为我们可以预期SerializableGenerator可以在json.dumps之前立即调用。(针对用户1158559解决方案)</li>
<li>不必通过NotImplementedError重写许多方法,因为这些方法并不都是像<code>__repr__</code>这样的方法。最好将生成器也存储到列表中,以提供有意义的结果,如<code>[<generator object ...>]</code>。(反对克劳德)。默认方法<code>__len__</code>和<code>__bool__</code>现在可以正确地识别空对象和非空对象。</li>
</ul>
<hr/>
<p>此解决方案的一个优点是,可以使用标准的JSON序列化程序而无需参数。如果应该支持嵌套生成器,或者不希望使用<code>SerializableGenerator(iterator)</code>进行封装,那么我建议使用<a href="https://stackoverflow.com/a/45482776/448474">IterEncoder</a>答案。</p>