Python 将输出序列化为 JSON - ValueError:检测到循环引用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14249115/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 10:52:48  来源:igfitidea点击:

Serializing output to JSON - ValueError: Circular reference detected

pythonjsonpython-2.7

提问by pisarzp

I'm trying to output results of my mysql query to JSON. I have problem with serializing datetime.datetime field, so I wrote small function to do that:

我正在尝试将 mysql 查询的结果输出到 JSON。我在序列化 datetime.datetime 字段时遇到问题,所以我写了一个小函数来做到这一点:

def date_handler(obj):
    if hasattr(obj, 'isoformat'):
        return obj.isoformat()
    else:
        return obj

and then in main code I'm just running:

然后在主代码中我只是运行:

products_json = []
for code in best_matching_codes:
    cur = db.cursor()
    query = "SELECT * FROM %s WHERE code LIKE '%s'" % (PRODUCTS_TABLE_NAME, product_code)
    cur.execute(query)
    columns = [desc[0] for desc in cur.description]
    rows = cur.fetchall()
    for row in rows:
        products_json.append(dict((k,v) for k,v in zip(columns,row)))   

return json.dumps(products_json, default = date_handler)

However, since I wrote date_handler function, I'm getting "ValueError: Circular reference detected"

但是,由于我编写了 date_handler 函数,因此收到“ValueError:检测到循环引用”

127.0.0.1 - - [10/Jan/2013 00:42:18] "GET /1/product?code=9571%2F702 HTTP/1.1" 500 -
Traceback (most recent call last):
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1701, in __call__
return self.wsgi_app(environ, start_response)
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1689, in wsgi_app
response = self.make_response(self.handle_exception(e))
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1687, in wsgi_app
response = self.full_dispatch_request()
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1360, in full_dispatch_request
rv = self.handle_user_exception(e)
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1358, in full_dispatch_request
rv = self.dispatch_request()
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1344, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/pisarzp/Desktop/SusyChoosy/susyAPI/test1.py", line 69, in product_search
return json.dumps(products_json, default = date_handler)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py", line 238, in dumps
**kw).encode(obj)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 201, in encode
chunks = self.iterencode(o, _one_shot=True)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 264, in iterencode
return _iterencode(o, 0)
ValueError: Circular reference detected

What did I break? Is there a better way to serialize output to JSON?

我打破了什么?有没有更好的方法将输出序列化为 JSON?

回答by Blckknght

The function you pass as the defaultargument will only be called for objects that are not natively serializable by the jsonmodule. It must return a serializable object, or raise a TypeError.

您作为default参数传递的函数只会被json模块本身不可序列化的对象调用。它必须返回一个可序列化的对象,或者引发一个 TypeError。

Your version returns the same object you were passed if it's not of the one type you're fixing (dates). That is causing the circular reference error (which is misleading, since the circle is between one object and itself after being processed by date_handler).

如果它不是您正在修复的一种类型(日期),您的版本将返回与您传递的相同对象。这会导致循环引用错误(这是一种误导,因为在被 处理后,圆位于一个对象与其自身之间date_handler)。

You can start to fix this by changing date_handlerto raise an exception in its elseblock. That will still probably fail, but you can probably then find out what object it is that is in your data structure causing the problem using code like this:

您可以通过更改date_handler在其else块中引发异常来开始解决此问题。这仍然可能会失败,但是您可能可以使用如下代码找出数据结构中导致问题的对象:

def date_handler(obj):
    if hasattr(obj, 'isoformat'):
        return obj.isoformat()
    else:
        raise TypeError(
            "Unserializable object {} of type {}".format(obj, type(obj))
        )

回答by Joren Van Severen

Instead of raising the TypeErroryourself, you should relay the call to JSONEncoder's default-method:

TypeError您应该将调用中继到JSONEncoder的默认方法,而不是提高自己:

def date_handler(obj):
    if hasattr(obj, 'isoformat'):
        return obj.isoformat()
    else:
        json.JSONEncoder.default(self,obj)

This will also raise TypeErrorand is a better practice, it allows for JSONEncoderto try and encode the type your method can't.

这也将提高TypeError并且是一个更好的实践,它允许JSONEncoder尝试和编码您的方法不能的类型。

回答by GrvTyagi

json.dumps(obj, default=method_name)

"method_name" function must be return a serialize object.

“method_name”函数必须返回一个序列化对象。

def method_name(obj):
    data = {
            '__class__': obj.__class__.__name__,
            '__module__': obj.__module__
           }
    data.update(obj.__dict__)
    return data