首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >怎样才能让Python jsonpickle递归地工作?

怎样才能让Python jsonpickle递归地工作?
EN

Stack Overflow用户
提问于 2013-01-15 08:58:35
回答 3查看 3.4K关注 0票数 3

我在让Python的jsonpickle 0.4.0“递归”到包含自定义对象的自定义对象时遇到了麻烦。下面是显示我的问题的示例代码。

代码语言:javascript
复制
import jsonpickle
import jsonpickle.handlers

class Ball(object):
    def __init__(self, color):
        self.color = color

class Box(object):
    def __init__(self, *args):
        self.contents = args

class BallHandler(jsonpickle.handlers.BaseHandler):    
    def flatten(self, obj, data):
        data['color'] = obj.color
        return data

class BoxHandler(jsonpickle.handlers.BaseHandler):    
    def flatten(self, obj, data):
        data['contents'] = obj.contents
        return data

jsonpickle.handlers.registry.register(Ball, BallHandler)
jsonpickle.handlers.registry.register(Box, BoxHandler)

# works OK -- correctly prints: {"color": "white"}
white_ball = Ball('white')
print jsonpickle.encode(white_ball, unpicklable=False)

# works OK -- correctly prints: [{"color": "white"}, {"color": "green"}]
green_ball = Ball('green')
balls = [white_ball, green_ball]
print jsonpickle.encode(balls, unpicklable=False)

# works OK -- correctly prints: {"contents": [1, 2, 3, 4]}
box_1 = Box(1, 2, 3, 4)
print jsonpickle.encode(box_1, unpicklable=False)

# dies with "Ball object is not JSON serializable"
box_2 = Box(white_ball, green_ball)
print jsonpickle.encode(box_2, unpicklable=False)

球有“颜色”,盒子有“内容”。如果我有一个原生的Ball数组,那么jsonpickle就可以工作。如果我有一个原生int的盒子,那么jsonpickle就可以工作了。

但如果我有一盒球,jsonpickle"Ball object is not JSON serializable"炸弹。

从堆栈跟踪中,我预感到编码器将离开jsonpickle,转而使用其他JSON库……显然不知道我已经注册了BallHandler。

我该怎么解决这个问题呢?

顺便说一下,我的示例没有明确使用Django的任何部分,但我需要在Django应用程序中使用它。

提前感谢您的任何意见!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-06-21 10:39:10

我认为您可以回调到酸洗上下文以继续酸洗。

代码语言:javascript
复制
class BoxHandler(jsonpickle.handlers.BaseHandler):
def flatten(self, obj, data):
    return [self.context.flatten(x,reset=False) for x in obj.contents]

这似乎类似于pickler.py:44中内置的_list_recurse()函数处理这种情况的方式,因为flatten()只是调用self._flatten (在可选地重置状态变量之后)。

def _list_recurse(self, obj): return [self._flatten(v) for v in obj]

我现在正在对此进行测试,_depth似乎如预期的那样得到了维护。

票数 3
EN

Stack Overflow用户

发布于 2013-01-15 09:08:14

首先,为什么首先要创建自定义处理程序?您正在尝试做与默认处理程序已经做过的完全相同的事情。删除这两行register代码,并使用和不使用unpicklable=False对所有这些对象调用encode,您将获得相同的结果-除了它将完全按照您希望的方式处理装满球的盒子,而不是失败。

如果您通读教程、API、测试用例和示例,就会发现它们从未创建自定义处理程序来模拟这样的集合。(例如,看看测试套件(samples.pydocument_test.py)中的Node/Document/Section类。)所以,我认为你正在尝试做一些你不希望做的事情,也不打算做的事情。

但是,让我们看看你的实际问题:为什么它不工作?

好吧,这个很简单。你做错了。根据BaseHandler.flatten的文档,您应该:

将obj扁平化为json友好的形式。

因此,考虑到以下情况:

代码语言:javascript
复制
class BoxHandler(jsonpickle.handlers.BaseHandler):    
    def flatten(self, obj, data):
        data['contents'] = obj.contents
        return data

您有效地保证了obj.contents是JSON友好的形式。但它不是;它是Ball对象的list

那么,正确的答案是什么呢?嗯,你可以像你被展平一样展平内容中的每个元素。您可能认为有一些简单的方法可以做到这一点,但老实说,我在API、文档、示例或单元测试中看不到任何东西,所以我猜没有,所以您必须手动完成。大概是这样的(未经测试):

代码语言:javascript
复制
class BoxHandler(jsonpickle.handlers.BaseHandler):    
    def flatten(self, obj, data):
        p = jsonpickle.Pickler()
        data['contents'] = [p.flatten(elem) for elem in obj.contents]
        return data

但是…由于您得到的不是用来筛选您的相同Pickler --我看不出有任何方法可以--这很可能会违反encodemaxdepthunpicklable参数。

因此,也许没有正确的方法来做到这一点。

票数 4
EN

Stack Overflow用户

发布于 2013-01-15 09:21:25

如果jsonpickle与向json添加自定义对象处理有关,那么它应该集成到后者中,而不是试图为其“预处理”内容。要求用户自己处理这件事的现状是,as abarnert said将责任推到了另一个人的头上。

如果我是你,我会自己解决这个问题,或者让我的对象像JSON一样友好--比如让它们看起来像原生Python数据结构(JSON是原生Python数据结构的替代表示)。一种更简单的方法是避免这样的构造,这当然是一种杂乱无章的东西。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14329531

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档