Hoe maak je een klasse JSON serialiseerbaar

Hoe maak je een Python-klasse serialiseerbaar?

Een eenvoudige les:

class FileItem:
    def __init__(self, fname):
        self.fname = fname

Wat moet ik doen om output te krijgen van:

>>> import json
>>> my_file = FileItem('/foo/bar')
>>> json.dumps(my_file)
TypeError: Object of type 'FileItem' is not JSON serializable

Zonder de fout


Antwoord 1, autoriteit 100%

Heb je een idee over de verwachte output? Is dit bijvoorbeeld voldoende?

>>> f  = FileItem("/foo/bar")
>>> magic(f)
'{"fname": "/foo/bar"}'

In dat geval kun je gewoon json.dumps(f.__dict__)aanroepen.

Als u meer aangepaste uitvoer wilt, moet u JSONEncoderen implementeer uw eigen aangepaste serialisatie.

Zie hieronder voor een triviaal voorbeeld.

>>> from json import JSONEncoder
>>> class MyEncoder(JSONEncoder):
        def default(self, o):
            return o.__dict__    
>>> MyEncoder().encode(f)
'{"fname": "/foo/bar"}'

Vervolgens geef je deze les door aan de json.dumps()methode als clskwarg:

json.dumps(cls=MyEncoder)

Als u ook wilt decoderen, moet u een aangepaste object_hookopgeven voor de JSONDecoderklasse. Bijvoorbeeld:

>>> def from_json(json_object):
        if 'fname' in json_object:
            return FileItem(json_object['fname'])
>>> f = JSONDecoder(object_hook = from_json).decode('{"fname": "/foo/bar"}')
>>> f
<__main__.FileItem object at 0x9337fac>
>>> 

Antwoord 2, autoriteit 99%

Hier is een eenvoudige oplossing voor een eenvoudige functie:

.toJSON()Methode

In plaats van een JSON-serialiseerbare klasse, implementeert u een serialisatiemethode:

import json
class Object:
    def toJSON(self):
        return json.dumps(self, default=lambda o: o.__dict__, 
            sort_keys=True, indent=4)

Dus je noemt het gewoon om te serialiseren:

me = Object()
me.name = "Onur"
me.age = 35
me.dog = Object()
me.dog.name = "Apollo"
print(me.toJSON())

zal uitvoeren:

{
    "age": 35,
    "dog": {
        "name": "Apollo"
    },
    "name": "Onur"
}

Antwoord 3, autoriteit 32%

Voor complexere lessen kun je de tool jsonpickleoverwegen:

jsonpickle is een Python-bibliotheek voor serialisatie en deserialisatie van complexe Python-objecten van en naar JSON.

De standaard Python-bibliotheken voor het coderen van Python in JSON, zoals de Stdlib JSON, SimpleJson en Demjson, kan alleen Python Primitives omgaan met een Direct JSON-equivalent (b.v. Dictten, lijsten, snaren, inten, enz.). Jsonpickle bouwt bovenop deze bibliotheken en biedt meer complexe datastructuren om te worden geserialiseerd aan JSON. Jsonpickle is zeer configureerbaar en uitbreidbaar, waardoor de gebruiker de JSON-backend kan kiezen en extra backdsds toevoegen.


4, Autoriteit 9%

Ik hou van ONOR’s antwoord , maar zou uitbreiden tot een optionele toJSON()methode voor objecten om zichzelf te serialiseren:

def dumper(obj):
    try:
        return obj.toJSON()
    except:
        return obj.__dict__
print json.dumps(some_big_object, default=dumper, indent=2)

5, Autoriteit 7%

Voeg gewoon to_jsonMETHODE toe aan uw klas als volgt:

def to_json(self):
  return self.message # or how you want it to be serialized

en voeg deze code toe (van dit antwoord ) , naar ergens bovenaan alles:

from json import JSONEncoder
def _default(self, obj):
    return getattr(obj.__class__, "to_json", _default.default)(obj)
_default.default = JSONEncoder().default
JSONEncoder.default = _default

Dit zal Monkey-Patch JSON-module wanneer het wordt geïmporteerd
Jsonencoder.default () controleert automatisch op een speciale “to_json ()”
methode en gebruikt het om het object te coderen indien gevonden.

Net zoals Onur zei, maar deze keer hoeft u niet elke json.dumps()in uw project te bijwerken.


6, Autoriteit 6%

Een andere optie is om JSON Dumping in zijn eigen klasse te wikkelen:

import json
class FileItem:
    def __init__(self, fname):
        self.fname = fname
    def __repr__(self):
        return json.dumps(self.__dict__)

Of, nog beter, subclasseer FileItem-klasse van een JsonSerializableKlasse:

import json
class JsonSerializable(object):
    def toJson(self):
        return json.dumps(self.__dict__)
    def __repr__(self):
        return self.toJson()
class FileItem(JsonSerializable):
    def __init__(self, fname):
        self.fname = fname

Testen:

>>> f = FileItem('/foo/bar')
>>> f.toJson()
'{"fname": "/foo/bar"}'
>>> f
'{"fname": "/foo/bar"}'
>>> str(f) # string coercion
'{"fname": "/foo/bar"}'

Antwoord 7, autoriteit 5%

Zoals vermeld in veel andere antwoorden, kunt u een functie doorgeven aan json.dumpsom objecten die niet tot een van de standaard ondersteunde typen behoren, te converteren naar een ondersteund type. Verrassend genoeg noemt geen van hen het eenvoudigste geval, namelijk het gebruik van de ingebouwde functie varsom objecten om te zetten in een dictaat dat al hun attributen bevat:

json.dumps(obj, default=vars)

Merk op dat dit alleen basisgevallen dekt. Als u meer specifieke serialisatie nodig heeft voor bepaalde typen (bijv. bepaalde attributen uitsluiten of voor objecten die geen __dict__attribuut hebben), moet u een aangepast functie of een JSONEncoderzoals beschreven in de andere antwoorden.


Antwoord 8, autoriteit 5%

Ik kwam dit probleem onlangs tegen en implementeerde een meer algemene versie van een Encoder voor Python-objecten die geneste objectenen overgenomen veldenkan verwerken:

import json
import inspect
class ObjectEncoder(json.JSONEncoder):
    def default(self, obj):
        if hasattr(obj, "to_json"):
            return self.default(obj.to_json())
        elif hasattr(obj, "__dict__"):
            d = dict(
                (key, value)
                for key, value in inspect.getmembers(obj)
                if not key.startswith("__")
                and not inspect.isabstract(value)
                and not inspect.isbuiltin(value)
                and not inspect.isfunction(value)
                and not inspect.isgenerator(value)
                and not inspect.isgeneratorfunction(value)
                and not inspect.ismethod(value)
                and not inspect.ismethoddescriptor(value)
                and not inspect.isroutine(value)
            )
            return self.default(d)
        return obj

Voorbeeld:

class C(object):
    c = "NO"
    def to_json(self):
        return {"c": "YES"}
class B(object):
    b = "B"
    i = "I"
    def __init__(self, y):
        self.y = y
    def f(self):
        print "f"
class A(B):
    a = "A"
    def __init__(self):
        self.b = [{"ab": B("y")}]
        self.c = C()
print json.dumps(A(), cls=ObjectEncoder, indent=2, sort_keys=True)

Resultaat:

{
  "a": "A", 
  "b": [
    {
      "ab": {
        "b": "B", 
        "i": "I", 
        "y": "y"
      }
    }
  ], 
  "c": {
    "c": "YES"
  }, 
  "i": "I"
}

Antwoord 9, autoriteit 5%

Als je Python3.5+ gebruikt, kun je jsons. (PyPi: https://pypi.org/project/jsons/) Het zal je object converteren (en al zijn attributen recursief) naar een dictaat.

import jsons
a_dict = jsons.dump(your_object)

Of als je een string wilt:

a_str = jsons.dumps(your_object)

Of als uw klas jsons.JsonSerializableheeft geïmplementeerd:

a_dict = your_object.json

Antwoord 10, autoriteit 2%

import simplejson
class User(object):
    def __init__(self, name, mail):
        self.name = name
        self.mail = mail
    def _asdict(self):
        return self.__dict__
print(simplejson.dumps(User('alice', '[email protected]')))

als u standaard jsongebruikt, moet u een default-functie

definiëren

import json
def default(o):
    return o._asdict()
print(json.dumps(User('alice', '[email protected]'), default=default))

Antwoord 11

jsonis beperkt in termen van objecten die het kan afdrukken, en jsonpickle(je hebt mogelijk een pip install jsonpicklenodig) is beperkt in termen het kan geen tekst laten inspringen. Als je de inhoud wilt inspecteren van een object waarvan je de klasse niet kunt wijzigen, kon ik nog steeds geen rechtere manier vinden dan:

import json
 import jsonpickle
 ...
 print  json.dumps(json.loads(jsonpickle.encode(object)), indent=2)

Opmerking: ze kunnen de objectmethoden nog steeds niet afdrukken.


Antwoord 12

Deze klasse kan het lukken, het converteert het object naar standaard json.

import json
class Serializer(object):
    @staticmethod
    def serialize(object):
        return json.dumps(object, default=lambda o: o.__dict__.values()[0])

gebruik:

Serializer.serialize(my_object)

werkt in python2.7en python3.


Antwoord 13

Hier is mijn 3 cent …
Dit demonstreert expliciete json-serialisatie voor een boomachtig python-object.
Opmerking: als je echt code zoals deze wilt, kun je de twisted
FilePath
klasse.

import json, sys, os
class File:
    def __init__(self, path):
        self.path = path
    def isdir(self):
        return os.path.isdir(self.path)
    def isfile(self):
        return os.path.isfile(self.path)
    def children(self):        
        return [File(os.path.join(self.path, f)) 
                for f in os.listdir(self.path)]
    def getsize(self):        
        return os.path.getsize(self.path)
    def getModificationTime(self):
        return os.path.getmtime(self.path)
def _default(o):
    d = {}
    d['path'] = o.path
    d['isFile'] = o.isfile()
    d['isDir'] = o.isdir()
    d['mtime'] = int(o.getModificationTime())
    d['size'] = o.getsize() if o.isfile() else 0
    if o.isdir(): d['children'] = o.children()
    return d
folder = os.path.abspath('.')
json.dump(File(folder), sys.stdout, default=_default)

Antwoord 14

import json
class Foo(object):
    def __init__(self):
        self.bar = 'baz'
        self._qux = 'flub'
    def somemethod(self):
        pass
def default(instance):
    return {k: v
            for k, v in vars(instance).items()
            if not str(k).startswith('_')}
json_foo = json.dumps(Foo(), default=default)
assert '{"bar": "baz"}' == json_foo
print(json_foo)

Antwoord 15

jaracogaf een behoorlijk netjes antwoord. Ik moest wat kleine dingen repareren, maar dit werkt:

Code

# Your custom class
class MyCustom(object):
    def __json__(self):
        return {
            'a': self.a,
            'b': self.b,
            '__python__': 'mymodule.submodule:MyCustom.from_json',
        }
    to_json = __json__  # supported by simplejson
    @classmethod
    def from_json(cls, json):
        obj = cls()
        obj.a = json['a']
        obj.b = json['b']
        return obj
# Dumping and loading
import simplejson
obj = MyCustom()
obj.a = 3
obj.b = 4
json = simplejson.dumps(obj, for_json=True)
# Two-step loading
obj2_dict = simplejson.loads(json)
obj2 = MyCustom.from_json(obj2_dict)
# Make sure we have the correct thing
assert isinstance(obj2, MyCustom)
assert obj2.__dict__ == obj.__dict__

Houd er rekening mee dat we twee stappen nodig hebben om te laden. Voorlopig is de eigenschap __python__
wordt niet gebruikt.

Hoe vaak komt dit voor?

Met behulp van de methode van AlJohricontroleer ik de populariteit van benaderingen :

Serialisatie (Python -> JSON):

Deserialization (JSON – & GT, Python):


16

Dit heeft goed gewerkt voor mij:

class JsonSerializable(object):
    def serialize(self):
        return json.dumps(self.__dict__)
    def __repr__(self):
        return self.serialize()
    @staticmethod
    def dumper(obj):
        if "serialize" in dir(obj):
            return obj.serialize()
        return obj.__dict__

en dan

class FileItem(JsonSerializable):
    ...

en

log.debug(json.dumps(<my object>, default=JsonSerializable.dumper, indent=2))

17

Als je het niet erg vindt om een ​​pakket voor te installeren, kun je json-trucs gebruiken :

pip install json-tricks

Daarna moet u alleen dump(s)van json_tricksin plaats van JSON, en het werkt meestal:

from json_tricks import dumps
json_str = dumps(cls_instance, indent=4)

wat zal geven

{
        "__instance_type__": [
                "module_name.test_class",
                "MyTestCls"
        ],
        "attributes": {
                "attr": "val",
                "dct_attr": {
                        "hello": 42
                }
        }
}

En dat is het eigenlijk!


Dit werkt over het algemeen prima. Er zijn enkele uitzonderingen, b.v. als er speciale dingen gebeuren in __new__, of als er meer metaklasse magie aan de hand is.

Het laden werkt natuurlijk ook (wat heeft het anders voor zin):

from json_tricks import loads
json_str = loads(json_str)

Hiermee wordt aangenomen dat module_name.test_class.MyTestClskan worden geïmporteerd en niet op niet-compatibele manieren is gewijzigd. Je krijgt een instantie terug, niet een of ander woordenboek of zoiets, en het zou een identieke kopie moeten zijn als degene die je hebt gedumpt.

Als je wilt aanpassen hoe iets wordt (gede)serialiseerd, kun je speciale methoden aan je klas toevoegen, zoals:

class CustomEncodeCls:
        def __init__(self):
                self.relevant = 42
                self.irrelevant = 37
        def __json_encode__(self):
                # should return primitive, serializable types like dict, list, int, string, float...
                return {'relevant': self.relevant}
        def __json_decode__(self, **attrs):
                # should initialize all properties; note that __init__ is not called implicitly
                self.relevant = attrs['relevant']
                self.irrelevant = 12

die bijvoorbeeld slechts een deel van de attributenparameters serialiseert.

En als gratis bonus krijg je (de)serialisatie van numpy arrays, date & tijden, geordende kaarten en de mogelijkheid om opmerkingen in json op te nemen.

Disclaimer: ik heb json_tricksgemaakt, omdat ik hetzelfde probleem had als jij.


Antwoord 18

Kyle Delaney’s opmerking is correctdus ik heb geprobeerd het antwoord https://stackoverflow.com/a/15538391/1497139evenals een verbeterde versie van https://stackoverflow.com/a/10254820/1497139

om een “JSONAble” mixin te maken.

Dus om een klasse JSON-serialiseerbaar te maken, gebruikt u “JSONAble” als een superklasse en roept u ofwel:

instance.toJSON()

of

instance.asJSON()

voor de twee aangeboden methoden. Je zou de JSONAble-klasse ook kunnen uitbreiden met andere benaderingen die hier worden aangeboden.

Het testvoorbeeld voor de Eenheidstest met Gezins- en Persoonssteekproef resulteert in:

toJSON():

{
    "members": {
        "Flintstone,Fred": {
            "firstName": "Fred",
            "lastName": "Flintstone"
        },
        "Flintstone,Wilma": {
            "firstName": "Wilma",
            "lastName": "Flintstone"
        }
    },
    "name": "The Flintstones"
}

asJSON():

{'name': 'The Flintstones', 'members': {'Flintstone,Fred': {'firstName': 'Fred', 'lastName': 'Flintstone'}, 'Flintstone,Wilma': {'firstName': 'Wilma', 'lastName': 'Flintstone'}}}

Unit-test met familie- en persoonsvoorbeeld

def testJsonAble(self):
        family=Family("The Flintstones")
        family.add(Person("Fred","Flintstone")) 
        family.add(Person("Wilma","Flintstone"))
        json1=family.toJSON()
        json2=family.asJSON()
        print(json1)
        print(json2)
class Family(JSONAble):
    def __init__(self,name):
        self.name=name
        self.members={}
    def add(self,person):
        self.members[person.lastName+","+person.firstName]=person
class Person(JSONAble):
    def __init__(self,firstName,lastName):
        self.firstName=firstName;
        self.lastName=lastName;

jsonable.py definiëren jsonable mixin

'''
Created on 2020-09-03
@author: wf
'''
import json
class JSONAble(object):
    '''
    mixin to allow classes to be JSON serializable see
    https://stackoverflow.com/questions/3768895/how-to-make-a-class-json-serializable
    '''
    def __init__(self):
        '''
        Constructor
        '''
    def toJSON(self):
        return json.dumps(self, default=lambda o: o.__dict__, 
            sort_keys=True, indent=4)
    def getValue(self,v):
        if (hasattr(v, "asJSON")):
            return v.asJSON()
        elif type(v) is dict:
            return self.reprDict(v)
        elif type(v) is list:
            vlist=[]
            for vitem in v:
                vlist.append(self.getValue(vitem))
            return vlist
        else:   
            return v
    def reprDict(self,srcDict):
        '''
        get my dict elements
        '''
        d = dict()
        for a, v in srcDict.items():
            d[a]=self.getValue(v)
        return d
    def asJSON(self):
        '''
        recursively return my dict elements
        '''
        return self.reprDict(self.__dict__)   

U vindt deze benaderingen nu geïntegreerd in de https://github.com/wolfgangfahl/pylodstorageProject die beschikbaar is op https://pypi.org/project/pylodstorage/


19

JSONWEB lijkt de beste oplossing voor mij te zijn. Zie http://www.jsonweb.info/en/latest/

from jsonweb.encode import to_object, dumper
@to_object()
class DataModel(object):
  def __init__(self, id, value):
   self.id = id
   self.value = value
>>> data = DataModel(5, "foo")
>>> dumper(data)
'{"__type__": "DataModel", "id": 5, "value": "foo"}'

20

class DObject(json.JSONEncoder):
    def delete_not_related_keys(self, _dict):
        for key in ["skipkeys", "ensure_ascii", "check_circular", "allow_nan", "sort_keys", "indent"]:
            try:
                del _dict[key]
            except:
                continue
    def default(self, o):
        if hasattr(o, '__dict__'):
            my_dict = o.__dict__.copy()
            self.delete_not_related_keys(my_dict)
            return my_dict
        else:
            return o
a = DObject()
a.name = 'abdul wahid'
b = DObject()
b.name = a
print(json.dumps(b, cls=DObject))

Antwoord 21

Voortbouwend op Quinten Cabo‘s antwoord:

def sterilize(obj):
    """Make an object more ameniable to dumping as json
    """
    if type(obj) in (str, float, int, bool, type(None)):
        return obj
    elif isinstance(obj, dict):
        return {k: sterilize(v) for k, v in obj.items()}
    list_ret = []
    dict_ret = {}
    for a in dir(obj):
        if a == '__iter__' and callable(obj.__iter__):
            list_ret.extend([sterilize(v) for v in obj])
        elif a == '__dict__':
            dict_ret.update({k: sterilize(v) for k, v in obj.__dict__.items() if k not in ['__module__', '__dict__', '__weakref__', '__doc__']})
        elif a not in ['__doc__', '__module__']:
            aval = getattr(obj, a)
            if type(aval) in (str, float, int, bool, type(None)):
                dict_ret[a] = aval
            elif a != '__class__' and a != '__objclass__' and isinstance(aval, type):
                dict_ret[a] = sterilize(aval)
    if len(list_ret) == 0:
        if len(dict_ret) == 0:
            return repr(obj)
        return dict_ret
    else:
        if len(dict_ret) == 0:
            return list_ret
    return (list_ret, dict_ret)

De verschillen zijn

  1. Werkt voor elke iterable in plaats van alleen listen tuple(het werkt voor NumPy-arrays, enz.)
  2. Werkt voor dynamische typen (die een __dict__bevatten).
  3. Omvat native typen floaten Nonezodat ze niet worden geconverteerd naar string.
  4. Klassen met __dict__en leden zullen meestalwerken (als de namen van __dict__en leden met elkaar in botsing komen, krijg je er maar één – waarschijnlijk de lid)
  5. Klassen die lijsten zijn en leden hebben, zien eruit als een tupel van de lijst en een woordenboek
  6. Python3 (die isinstance()-aanroep mogelijkis het enige dat moet worden gewijzigd)

Antwoord 22

Ik vond de methode van Lost Koder het leukst. Ik kwam problemen tegen bij het serialiseren van complexere objecten waarvan de leden/methoden niet serialiseerbaar zijn. Dit is mijn implementatie die op meer objecten werkt:

class Serializer(object):
    @staticmethod
    def serialize(obj):
        def check(o):
            for k, v in o.__dict__.items():
                try:
                    _ = json.dumps(v)
                    o.__dict__[k] = v
                except TypeError:
                    o.__dict__[k] = str(v)
            return o
        return json.dumps(check(obj).__dict__, indent=2)

Antwoord 23

Ik kwam dit probleem tegen toen ik Peewee’s model probeerde op te slaan in PostgreSQL JSONField.

Na een tijdje worstelen, is hier de algemene oplossing.

De sleutel tot mijn oplossing is de broncode van Python doornemen en beseffen dat de codedocumentatie (beschreven hier) legt al uit hoe je de bestaande json.dumpskunt uitbreiden om andere gegevenstypen te ondersteunen.

Stel dat u momenteel een model heeft dat enkele velden bevat die niet serialiseerbaar zijn naar JSON en dat het model dat het JSON-veld bevat er oorspronkelijk als volgt uitziet:

class SomeClass(Model):
    json_field = JSONField()

Definieer gewoon een aangepaste JSONEncoderals volgt:

class CustomJsonEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, SomeTypeUnsupportedByJsonDumps):
            return < whatever value you want >
        return json.JSONEncoder.default(self, obj)
    @staticmethod
    def json_dumper(obj):
        return json.dumps(obj, cls=CustomJsonEncoder)

En gebruik het dan gewoon in je JSONFieldzoals hieronder:

class SomeClass(Model):
    json_field = JSONField(dumps=CustomJsonEncoder.json_dumper)

De sleutel is de bovenstaande methode default(self, obj). Voor elke ... is not JSON serializableklacht die je van Python ontvangt, voeg gewoon code toe om het unserializable-to-JSON type af te handelen (zoals Enumof datetime)

Zo ondersteun ik bijvoorbeeld een klas die is geërfd van Enum:

class TransactionType(Enum):
   CURRENT = 1
   STACKED = 2
   def default(self, obj):
       if isinstance(obj, TransactionType):
           return obj.value
       return json.JSONEncoder.default(self, obj)

Ten slotte, met de code geïmplementeerd zoals hierboven, kun je alle Peewee-modellen converteren naar een JSON-seriazeerbaar object zoals hieronder:

peewee_model = WhateverPeeweeModel()
new_model = SomeClass()
new_model.json_field = model_to_dict(peewee_model)

Hoewel de bovenstaande code (enigszins) specifiek was voor Peewee, maar ik denk:

  1. Het is van toepassing op andere ORM’s (Django, enz.) in het algemeen
  2. Als je begrijpt hoe json.dumpswerkt, werkt deze oplossing ook in het algemeen ook met Python (zonder ORM)

Heeft u vragen, plaats deze dan in het opmerkingengedeelte. Bedankt!


Antwoord 24

Eerst moeten we ons object JSON-compatibel maken, zodat we het kunnen dumpen met de standaard JSON-module. Ik deed het op deze manier:

def serialize(o):
    if isinstance(o, dict):
        return {k:serialize(v) for k,v in o.items()}
    if isinstance(o, list):
        return [serialize(e) for e in o]
    if isinstance(o, bytes):
        return o.decode("utf-8")
    return o

Antwoord 25

Deze functie gebruikt recursie om elk deel van het woordenboek te herhalen en roept vervolgens de repr()-methoden aan van klassen die geen ingebouwde typen zijn.

def sterilize(obj):
    object_type = type(obj)
    if isinstance(obj, dict):
        return {k: sterilize(v) for k, v in obj.items()}
    elif object_type in (list, tuple):
        return [sterilize(v) for v in obj]
    elif object_type in (str, int, bool, float):
        return obj
    else:
        return obj.__repr__()

Antwoord 26

Ik heb mijn eigen oplossing bedacht. Gebruik deze methode, geef elk document (dict,list, ObjectIdenz.) door om te serialiseren.

def getSerializable(doc):
    # check if it's a list
    if isinstance(doc, list):
        for i, val in enumerate(doc):
            doc[i] = getSerializable(doc[i])
        return doc
    # check if it's a dict
    if isinstance(doc, dict):
        for key in doc.keys():
            doc[key] = getSerializable(doc[key])
        return doc
    # Process ObjectId
    if isinstance(doc, ObjectId):
        doc = str(doc)
        return doc
    # Use any other custom serializting stuff here...
    # For the rest of stuff
    return doc

Antwoord 27

Als je een pakket kunt installeren, raad ik aan om dillete proberen, wat werkte prima voor mijn project. Het leuke van dit pakket is dat het dezelfde interface heeft als pickle, dus als je al gebruik hebt gemaakt van picklein je project, kun je het gewoon vervangen door dillen kijk of het script wordt uitgevoerd, zonder enige code te wijzigen. Het is dus een erg goedkope oplossing om te proberen!

(Volledige anti-openbaarmaking: ik ben op geen enkele manier gelieerd aan en heb nooit bijgedragen aan het dille-project.)

Installeer het pakket:

pip install dill

Bewerk vervolgens je code om dillte importeren in plaats van pickle:

# import pickle
import dill as pickle

Voer je script uit en kijk of het werkt. (Als dit het geval is, wilt u misschien uw code opschonen, zodat u niet langer de naam van de pickle-module schaduwt!)

Enkele details over datatypes die dillwel en niet kunnen serialiseren, van de projectpagina :

dillkan de volgende standaardsoorten inmaken:

geen, type, bool, int, long, float, complex, str, unicode, tuple,
lijst, dict, bestand, buffer, ingebouwd, zowel oude als nieuwe stijlklassen,
Instances van oude en nieuwe stijlklassen, Set, FrozenSet, Array,
Functies, Uitzonderingen

dillkan ook pakken van meer ‘exotische’ standaardtypen:

Functies met rendementen, geneste functies, lambdas, cel, methode,
Niet-geboundmethod, module, code, methodwapper, dictProxy,
MethodDescriptor, GetSetDescriptor, MemberDescriptor,
WrapperDescriptor, Xrange, Slice, Notimplemented, Ellipsis, Stop

dillkan deze standaardtypen nog niet augstaan:

Frame, generator, traceback


28

Ik zie hier geen vermelding van seriële versie of backcompat, dus ik zal mijn oplossing plaatsen die ik een beetje gebruikt. Ik heb waarschijnlijk veel meer te leren, met name Java en Javascript zijn waarschijnlijk volwassener dan ik hier, maar hier gaat

https://gist.github.com/andy-d/b7878D0044A4242C0498ED6D67FD50FE


29

Om een ​​andere optie toe te voegen: u kunt de attrsPackage en de asdict-methode gebruiken.

class ObjectEncoder(JSONEncoder):
    def default(self, o):
        return attr.asdict(o)
json.dumps(objects, cls=ObjectEncoder)

en om terug te zetten

def from_json(o):
    if '_obj_name' in o:
        type_ = o['_obj_name']
        del o['_obj_name']
        return globals()[type_](**o)
    else:
        return o
data = JSONDecoder(object_hook=from_json).decode(data)

Klasse ziet er als volgt uit

@attr.s
class Foo(object):
    x = attr.ib()
    _obj_name = attr.ib(init=False, default='Foo')

Other episodes