Python อ็อบเจ็กต์ที่ทำให้เป็นอนุกรมได้ json

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 ของฉันเป็นอนุกรมได้หรือไม่? สิ่งที่ฉันกังวลคือการอ้างอิงแบบเรียกซ้ำ


person Community    schedule 22.09.2009    source แหล่งที่มา
comment
คำตอบนี้อาจมีประโยชน์: stackoverflow.com/a/28253689/303114   -  person danfromisrael    schedule 09.04.2015
comment
ชื่อคำถามของคุณคลุมเครือมาก คุณควรปรับปรุงมัน   -  person Charlie Parker    schedule 04.02.2017
comment
คำถามเดียวกันกับคำตอบแบบปิด: stackoverflow.com/a/7409526/2728644   -  person dasons    schedule 03.06.2017


คำตอบ (5)


เขียนตัวเข้ารหัสและตัวถอดรหัสของคุณเอง ซึ่งสามารถเรียบง่ายมากเช่น 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"}

คุณสามารถเขียนตัวถอดรหัสได้เช่นเดียวกัน แต่คุณจะต้องระบุว่าเป็นวัตถุของคุณหรือไม่ ดังนั้นคุณอาจใส่ประเภทได้เช่นกันหากจำเป็น

person Anurag Uniyal    schedule 22.09.2009
comment
เอกสารประกอบสำหรับ simplejson ระบุไว้อย่างชัดเจนว่าคุณควรเรียก JSONEncoder.default() เพื่อยกระดับ TypeError ดังนั้นฉันคิดว่ามันจะเป็นการดีกว่าถ้าแทนที่การ Raise ของคุณด้วยการเรียกสิ่งนั้น - person slacy; 03.01.2012
comment
หรือดีกว่านั้น ใช้คลาสย่อย [simple]json.JSONEncoder ของคุณเองและเขียนทับเมธอด default ด้วยเวอร์ชันที่ส่งคืนการแสดงอ็อบเจ็กต์ของคุณแบบอนุกรมได้ หรือการเรียก JSONEncoder.default สำหรับประเภทอื่นๆ ทั้งหมด ดู docs.python.org/library/json.html#json.JSONEncoder. - person Chris Arndt; 23.01.2012
comment
@ChrisArndt ไม่ใช่ว่าวิธีการข้างต้นของ Anurag ทำได้อย่างไร - person zakdances; 03.03.2013
comment
@ yourfiendzak ความคิดเห็นของฉันเก่ากว่าการแก้ไขคำตอบครั้งล่าสุด ดังนั้นฉันจึง probabyl อ้างถึงเวอร์ชันก่อนหน้า - person Chris Arndt; 19.03.2013

jsonpickle เพื่อชัยชนะ!

(เพิ่งมีคำถามเดียวกันนี้ ... json Pickle จัดการกราฟวัตถุแบบเรียกซ้ำ / ซ้อนตลอดจนการลัดวงจรสำหรับกราฟวัตถุแบบวนรอบ)

person longda    schedule 13.06.2012

คำตอบทางอ้อม: แทนที่จะใช้ JSON คุณสามารถใช้ YAML ซึ่งไม่มีปัญหาในการทำสิ่งที่คุณต้องการ (โดยพื้นฐานแล้ว JSON เป็นส่วนย่อยของ YAML)

ตัวอย่าง:

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

อันที่จริง YAML จัดการการอ้างอิงแบบวนให้คุณเป็นอย่างดี

person Eric O Lebigot    schedule 22.09.2009
comment
บทความที่น่าสนใจ แต่คำตอบนี้ ไม่มีการแก้ มีเพียง การดอง เท่านั้น (เช่น ไม่ใช่ load() แต่ dump()) - person Eric O Lebigot; 05.02.2013
comment
แน่นอน แต่มันก็คุ้มค่าที่จะจำไว้ นอกจากนี้ ทำไมคุณถึงดองอะไรบางอย่าง เว้นแต่คุณจะวางแผนจะใช้มันในภายหลัง?... - person Sardathrion - against SE abuse; 05.02.2013
comment
อย่างแท้จริง. อย่างไรก็ตาม จะปลอดภัยอย่างสมบูรณ์สำหรับ load() YAML dumped ด้วยโค้ดด้านบน (ไม่สามารถนำไปสู่การตีความโค้ด Python ได้ ยกเว้นข้อผิดพลาดใน PyYAML เนื่องจากซอร์สโค้ดแสดง [ไม่มีการแทรกโค้ด Python... ]) - person Eric O Lebigot; 05.02.2013
comment
ใช่ เราเห็นด้วย: มันจะปลอดภัยในกรณีนี้ แต่ไม่จำเป็นต้องเป็นทุกกรณี ฉันกำลังหวาดระแวงและคาดการณ์การใช้งานจากตัวอย่างของคุณ ดังนั้นเพียง (สิ่งที่เริ่มต้นจาก) ความคิดเห็นเล็ก ๆ - person Sardathrion - against SE abuse; 05.02.2013

ฉันใช้วิธี todict ที่ง่ายมากด้วยความช่วยเหลือของ https://stackoverflow.com/a/11637457/1766716

  • วนซ้ำคุณสมบัติที่ไม่ได้ขึ้นต้นด้วย __
  • กำจัดวิธีการต่างๆ
  • ลบคุณสมบัติบางอย่างด้วยตนเองซึ่งไม่จำเป็น (สำหรับกรณีของฉัน มาจาก 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()}
person guneysus    schedule 06.03.2016

วิธีแก้ปัญหาของฉันสำหรับสิ่งนี้คือการขยายคลาส 'dict' และทำการตรวจสอบเกี่ยวกับแอตทริบิวต์ที่จำเป็น/อนุญาตโดยการแทนที่วิธีการ init อัปเดต และตั้งค่าคลาส

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"
    }
)
person g.carey    schedule 25.06.2015