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 JSONEncoder
en 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 cls
kwarg:
json.dumps(cls=MyEncoder)
Als u ook wilt decoderen, moet u een aangepaste object_hook
opgeven voor de JSONDecoder
klasse. 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_json
METHODE 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 JsonSerializable
Klasse:
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.dumps
om 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 vars
om 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 JSONEncoder
zoals 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.JsonSerializable
heeft 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 json
gebruikt, 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
json
is beperkt in termen van objecten die het kan afdrukken, en jsonpickle
(je hebt mogelijk een pip install jsonpickle
nodig) 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.7
en 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
FilePathklasse.
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):
to_json
: 266.595 op 27-06-2018toJSON
: 96.307 op 27-06-2018__json__
: 8,504 op 2018-06-27- for_json: 6.937 op 2018-06-27
Deserialization (JSON – & GT, Python):
from_json
: 226.101 op 2018-06-27
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_tricks
in 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.MyTestCls
kan 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
- Werkt voor elke iterable in plaats van alleen
list
entuple
(het werkt voor NumPy-arrays, enz.) - Werkt voor dynamische typen (die een
__dict__
bevatten). - Omvat native typen
float
enNone
zodat ze niet worden geconverteerd naar string. - 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) - Klassen die lijsten zijn en leden hebben, zien eruit als een tupel van de lijst en een woordenboek
- 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.dumps
kunt 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 JSONEncoder
als 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 JSONField
zoals 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 serializable
klacht die je van Python ontvangt, voeg gewoon code toe om het unserializable-to-JSON type af te handelen (zoals Enum
of 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:
- Het is van toepassing op andere ORM’s (Django, enz.) in het algemeen
- Als je begrijpt hoe
json.dumps
werkt, 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 pickle
in je project, kun je het gewoon vervangen door dill
en 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 dill
te 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 dill
wel en niet kunnen serialiseren, van de projectpagina :
dill
kan 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
dill
kan 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
dill
kan 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 attrs
Package 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')