(answering my own question, more details or corrections welcomed) I have spent some time looking into these questions and I think I have better understanding now.
- Q: Is there no universal object serialization method in Python (to json)?
A: no there is not. Quoting @gilch,
There is no universal object serialization in Python, full stop.
The closest equivalent there is, appears to be the module jsonpickle though it has some security considerations. With this module, it's going to work for the reasonable majority of the objects, and can be further expanded to support e.g. numpy types, too. Where the serialized content goes outside, the serialization can be done with unpicklable=False, which generates the regular JSON form of a DTO one may expect from e.g. dotnet.
string = jsonpickle.dumps(person1, unpicklable=False)
print(string)
>> {"name": "Mike", "age": 34, "learnsPython": true, "controllers": ["XboX", "Super Nintendo"]}
For the round-robin, this parameter has to be omitted or set to true which results in some metadata field(s) added to the payload, but this enables the JSON to be converted back to the source object with loads():
string = jsonpickle.dumps(person1, unpicklable=False)
print(string)
>> {"py/object": "__main__.Person", "name": "Mike", "age": 34, "learnsPython": true, "controllers": ["XboX", "Super Nintendo"]
There is also a number of alternatives to be used with other libraries (e.g. json), namely dumps(myObject.__dict__), dumps(vars(myType)), etc., up to custom default() methods and type-specific serializers.
- Q:Why is this so?
A: (my speculation here based on the code I read) Since Python does not support constructor overloads, which eliminates for most of the types the availability of a parameterless constructor, serializing and deserializing types requires to have custom approach for a number of known types out there. This also calls for strict data contracts that serializers would have to adhere to in order to deserialize the objects back - and this is what pickle/jsonpickle does.
Speculation #2: I assume the decision to put the type into the data instead of allowing the caller to specify the type was done for the purpose of data integrity, and to follow the established pickle serialization practice.
Speculation #3: the generics only exist in Python since 3.5, so relatively recently, and hence are not yet used as a technique for deserialization.
(answering my own question, more details or corrections welcomed) I have spent some time looking into these questions and I think I have better understanding now.
- Q: Is there no universal object serialization method in Python (to json)?
A: no there is not. Quoting @gilch,
There is no universal object serialization in Python, full stop.
The closest equivalent there is, appears to be the module jsonpickle though it has some security considerations. With this module, it's going to work for the reasonable majority of the objects, and can be further expanded to support e.g. numpy types, too. Where the serialized content goes outside, the serialization can be done with unpicklable=False, which generates the regular JSON form of a DTO one may expect from e.g. dotnet.
string = jsonpickle.dumps(person1, unpicklable=False)
print(string)
>> {"name": "Mike", "age": 34, "learnsPython": true, "controllers": ["XboX", "Super Nintendo"]}
For the round-robin, this parameter has to be omitted or set to true which results in some metadata field(s) added to the payload, but this enables the JSON to be converted back to the source object with loads():
string = jsonpickle.dumps(person1, unpicklable=False)
print(string)
>> {"py/object": "__main__.Person", "name": "Mike", "age": 34, "learnsPython": true, "controllers": ["XboX", "Super Nintendo"]
There is also a number of alternatives to be used with other libraries (e.g. json), namely dumps(myObject.__dict__), dumps(vars(myType)), etc., up to custom default() methods and type-specific serializers.
- Q:Why is this so?
A: (my speculation here based on the code I read) Since Python does not support constructor overloads, which eliminates for most of the types the availability of a parameterless constructor, serializing and deserializing types requires to have custom approach for a number of known types out there. This also calls for strict data contracts that serializers would have to adhere to in order to deserialize the objects back - and this is what pickle/jsonpickle does.
Speculation #2: I assume the decision to put the type into the data instead of allowing the caller to specify the type was done for the purpose of data integrity, and to follow the established pickle serialization practice.
Speculation #3: the generics only exist in Python since 3.5, so relatively recently, and hence are not yet used as a technique for deserialization.
The pickle module can be used for binary serialization of most Python objects.
JSON can only represent a subset of Python by default. See the Python documentation's comparison of pickle and JSON for more details.
However, for many purposes, converting the dictionary representation of an object to JSON may be sufficient:
import json
class Person:
def __init__(self, name, age, learnsPython, controllers):
self.name = name
self.age = age
self.learnsPython = learnsPython
self.controllers = controllers
person = Person("Mike", 34, True, ['XboX', 'Super Nintendo'])
print(json.dumps(person.__dict__))
Output:
{"name": "Mike", "age": 34, "learnsPython": true, "controllers": ["XboX", "Super Nintendo"]}