在使用生成器的JSONEncoder上重写_iterencode方法的问题

0 投票
1 回答
549 浏览
提问于 2025-04-18 09:44

我正在尝试创建一个自定义的编码器,主要是想复用JSONEncoder的功能:

BinaryJSONEncoder(JSONEncoder):
    def _iterencode(self, o, markers):
        sys.stderr.write("Calling custom _iterencode\n")
        try:
             return JSONEncoder._iterencode(self, o, markers)
        except UnicodeDecodeError:
             sys.stderr.write("Got exception\n")
             return ""

但是,我仍然遇到了一个未处理的UnicodeDecodeError错误,因为一旦调用了_iterencode方法,它会在返回之前循环遍历它的生成器。奇怪的是,这个异常是从_iterencode方法中产生的,但我的方法在返回的调用栈中并不存在!不过我的函数确实被调用了,因为在Apache的错误日志中出现了“调用自定义_iterencode”的信息。我该如何解决这个问题,而不需要从头实现整个方法呢?

以下是调用栈:

Traceback (most recent call last):
  File "/var/www/radiator/cgi-bin/ldapsearch.py", line 108, in <module>
    res.body(json.dumps(res_data, cls=BinaryJSONEncoder))
  File "/usr/lib64/python2.6/json/__init__.py", line 237, in dumps
    **kw).encode(obj)
  File "/usr/lib64/python2.6/json/encoder.py", line 367, in encode
    chunks = list(self.iterencode(o))
  File "/usr/lib64/python2.6/json/encoder.py", line 306, in _iterencode
    for chunk in self._iterencode_list(o, markers):
  File "/usr/lib64/python2.6/json/encoder.py", line 204, in _iterencode_list
    for chunk in self._iterencode(value, markers):
  File "/usr/lib64/python2.6/json/encoder.py", line 306, in _iterencode
    for chunk in self._iterencode_list(o, markers):
  File "/usr/lib64/python2.6/json/encoder.py", line 204, in _iterencode_list
    for chunk in self._iterencode(value, markers):
  File "/usr/lib64/python2.6/json/encoder.py", line 309, in _iterencode
    for chunk in self._iterencode_dict(o, markers):
  File "/usr/lib64/python2.6/json/encoder.py", line 275, in _iterencode_dict
    for chunk in self._iterencode(value, markers):
  File "/usr/lib64/python2.6/json/encoder.py", line 306, in _iterencode
    for chunk in self._iterencode_list(o, markers):
  File "/usr/lib64/python2.6/json/encoder.py", line 204, in _iterencode_list
    for chunk in self._iterencode(value, markers):
  File "/usr/lib64/python2.6/json/encoder.py", line 294, in _iterencode
    yield encoder(o)
UnicodeDecodeError: 'utf8' codec can't decode byte 0xc3 in position 2: invalid continuation byte

1 个回答

0

看起来解决这个问题的唯一可行方法就是重新实现整个函数,并为二进制数据添加处理程序:

从 json.encoder 导入 encode_basestring_ascii 和 encode_basestring

class BinaryJSONEncoder(JSONEncoder):
    def _iterencode(self, o, markers=None):
        if isinstance(o, str):
            try:
                o = unicode(o, "utf8")
            except UnicodeDecodeError:
                o = base64.b64encode(o)

        if isinstance(o, basestring):
            if self.ensure_ascii:
                encoder = encode_basestring_ascii
            else:
                encoder = encode_basestring
            _encoding = self.encoding
            if (_encoding is not None and isinstance(o, str)
                    and not (_encoding == 'utf-8')):
                o = o.decode(_encoding)
            yield encoder(o)
        elif o is None:
            yield 'null'
        elif o is True:
            yield 'true'
        elif o is False:
            yield 'false'
        elif isinstance(o, (int, long)):
            yield str(o)
        elif isinstance(o, float):
            yield floatstr(o, self.allow_nan)
        elif isinstance(o, (list, tuple)):
            for chunk in self._iterencode_list(o, markers):
                yield chunk
        elif isinstance(o, dict):
            for chunk in self._iterencode_dict(o, markers):
                yield chunk
        else:
            if markers is not None:
                markerid = id(o)
                if markerid in markers:
                    raise ValueError("Circular reference detected")
                markers[markerid] = o
            for chunk in self._iterencode_default(o, markers):
                yield chunk
            if markers is not None:
                del markers[markerid]

我明白当抛出异常时,生成器会退出的问题,但为什么在那之后不能调用父类的方法呢?这样的话只会调用父类的方法吗?

撰写回答