【问题标题】:Python serializable objects jsonPython 可序列化对象 json
【发布时间】:2010-11-30 07:35:03
【问题描述】:
class gpagelet:
    """
    Holds   1) the pagelet xpath, which is a string
            2) the list of pagelet shingles, list
    """
    def __init__(self, parent):
        if not isinstance( parent, gwebpage):
            raise Exception("Parent must be an instance of gwebpage")
        self.parent = parent    # This must be a gwebpage instance
        self.xpath = None       # String
        self.visibleShingles = [] # list of tuples
        self.invisibleShingles = [] # list of tuples
        self.urls = [] # list of string

class gwebpage:
    """
    Holds all the datastructure after the results have been parsed
    holds:  1) lists of gpagelets
            2) loc, string, location of the file that represents it
    """
    def __init__(self, url):
        self.url = url              # Str
        self.netloc = False         # Str
        self.gpagelets = []         # gpagelets instance
        self.page_key = ""          # str

有没有办法让我的类 json 可序列化?我担心的是递归引用。

【问题讨论】:

标签: python json serializable


【解决方案1】:

编写自己的编码器和解码器,可以很简单,比如return __dict__

例如这是一个转储完全递归树结构的编码器,您可以对其进行增强或将其用于您自己的目的

import json

class Tree(object):
    def __init__(self, name, childTrees=None):
        self.name = name
        if childTrees is None:
            childTrees = []
        self.childTrees = childTrees

class MyEncoder(json.JSONEncoder):
    def default(self, obj):
        if not isinstance(obj, Tree):
            return super(MyEncoder, self).default(obj)

        return obj.__dict__

c1 = Tree("c1")
c2 = Tree("c2") 
t = Tree("t",[c1,c2])

print json.dumps(t, cls=MyEncoder)

打印出来

{"childTrees": [{"childTrees": [], "name": "c1"}, {"childTrees": [], "name": "c2"}], "name": "t"}

你可以类似地编写一个解码器,但你需要以某种方式确定它是否是你的对象,所以如果需要你也可以输入一个类型。

【讨论】:

  • simplejson 的文档明确指出你应该调用 JSONEncoder.default() 来引发 TypeError,所以我认为最好用调用它来替换你的 raise。
  • 或者更好的是,实现您自己的[simple]json.JSONEncoder 子类并使用返回对象的可序列化表示或为所有其他类型调用JSONEncoder.default 的版本覆盖default 方法。见docs.python.org/library/json.html#json.JSONEncoder
  • @ChrisArndt 这不是 Anurag 的上述方法吗?
  • @yourfiendzak 我的评论比答案的最后编辑旧,所以我可能指的是早期版本。
【解决方案2】:

间接回答:您可以使用YAML,而不是使用 JSON,这可以满足您的需求。 (JSON 本质上是 YAML 的一个子集。)

例子:

import yaml
o1 = gwebpage("url")
o2 = gpagelet(o1)
o1.gpagelets = [o2]
print yaml.dump(o1)

事实上,YAML 可以很好地为您处理循环引用。

【讨论】:

  • 有趣的文章,但是这个答案中没有没有解酸,只有酸洗(即没有load(),而是dump())。
  • 确实,但值得牢记。再说了,除非你以后打算用,不然为什么要腌制呢?...
  • 确实如此。但是,load() YAML dumped 通过上面的代码 是完全安全的(它不能导致 Python 代码的解释,除了 PyYAML 中的一个错误,因为源代码显示 [no Python 代码注入...]).
  • 是的,我们同意:在 this 情况下它安全的,但在所有情况下不一定是安全的。我很偏执,从你的例子中推断出用途。因此只是(开始时)一个小评论。
【解决方案3】:

我在https://stackoverflow.com/a/11637457/1766716的帮助下实现了一个非常简单的todict方法

  • 迭代不是以__ 开头的属性
  • 消除方法
  • 手动消除一些不必要的属性(对于我来说,来自 sqlalcemy)

并使用getattr构建字典。

class User(Base):
    id = Column(Integer, primary_key=True)
    firstname = Column(String(50))
    lastname = Column(String(50))
    password = Column(String(20))
    def props(self):
        return filter(
            lambda a:
            not a.startswith('__')
            and a not in ['_decl_class_registry', '_sa_instance_state', '_sa_class_manager', 'metadata']
            and not callable(getattr(self, a)),
            dir(self))
    def todict(self):
        return {k: self.__getattribute__(k) for k in self.props()}

【讨论】:

    【解决方案4】:

    对此我的解决方案是扩展“dict”类,并通过覆盖 init、update 和 set 类方法来检查所需/允许的属性。

    class StrictDict(dict):
        required=set()
        at_least_one_required=set()
        cannot_coexist=set()
        allowed=set()
        def __init__(self, iterable={}, **kwargs):
            super(StrictDict, self).__init__({})
            keys = set(iterable.keys()).union(set(kwargs.keys()))
            if not keys.issuperset(self.required):
                msg = str(self.__class__.__name__) + " requires: " + str([str(key) for key in self.required])
                raise AttributeError(msg)
            if len(list(self.at_least_one_required)) and len(list(keys.intersection(self.at_least_one_required))) < 1:
                msg = str(self.__class__.__name__) + " requires at least one: " + str([str(key) for key in self.at_least_one_required])
                raise AttributeError(msg)
            for key, val in iterable.iteritems():
                self.__setitem__(key, val)
            for key, val in kwargs.iteritems():
                self.__setitem__(key, val)
    
        def update(self, E=None, **F):
            for key, val in E.iteritems():
                self.__setitem__(key, val)
            for key, val in F.iteritems():
                self.__setitem__(key, val)
            super(StrictDict, self).update({})
    
        def __setitem__(self, key, value):
            all_allowed = self.allowed.union(self.required).union(self.at_least_one_required).union(self.cannot_coexist)
            if key not in list(all_allowed):
                msg = str(self.__class__.__name__) + " does not allow member '" + key + "'"
                raise AttributeError(msg)
            if key in list(self.cannot_coexist):
                for item in list(self.cannot_coexist):
                    if key != item and item in self.keys():
                        msg = str(self.__class__.__name__) + "does not allow members '" + key + "' and '" + item + "' to coexist'"
                        raise AttributeError(msg)
            super(StrictDict, self).__setitem__(key, value)
    

    示例用法:

    class JSONDoc(StrictDict):
        """
        Class corresponding to JSON API top-level document structure
        http://jsonapi.org/format/#document-top-level
        """
        at_least_one_required={'data', 'errors', 'meta'}
        allowed={"jsonapi", "links", "included"}
        cannot_coexist={"data", "errors"}
        def __setitem__(self, key, value):
            if key == "included" and "data" not in self.keys():
                msg = str(self.__class__.__name__) + " does not allow 'included' member if 'data' member is not present"
                raise AttributeError(msg)
            super(JSONDoc, self).__setitem__(key, value)
    
    json_doc = JSONDoc(
        data={
            "id": 5,
            "type": "movies"
        },
        links={
            "self": "http://url.com"
        }
    )
    

    【讨论】:

      猜你喜欢
      • 2017-02-11
      • 2017-09-03
      • 2018-11-15
      • 1970-01-01
      • 2019-08-29
      • 1970-01-01
      • 2021-11-05
      • 2019-07-23
      • 2010-12-29
      相关资源
      最近更新 更多