We've heard a lot about Python serialization and deserialization

  • 2020-06-07 04:44:16
  • OfStack

By serializing the object, it can be stored in variables or files, and the state of the object at that time can be saved and its life cycle can be extended. And the object can be read out again as needed. Several common modules in Python enable this functionality.

pickle module

Stored in variables

dumps(obj) returns the bytes stored


dic = {'age': 23, 'job': 'student'}
byte_data = pickle.dumps(dic)
# out -> b'\x80\x03}q\x00(X\x03\x00\x00\...'
print(byte_data)

Read the data

The data is stored in bytes in the byte_data variable, using the loads function when it needs to be used again.


obj = pickle.loads(byte_data)
print(obj)

Stored in a file

It can also be stored in a file to make the object persistent. The dump and load functions are used, but note the difference with s. Since pickle writes base 2 data, it needs to be opened in wb and rb modes.


#  serialization 
with open('abc.pkl', 'wb') as f:
  dic = {'age': 23, 'job': 'student'}
  pickle.dump(dic, f)
#  deserialization 
with open('abc.pkl', 'rb') as f:
  aa = pickle.load(f)
  print(aa)
  print(type(aa)) # <class 'dict'>

Serialize user-defined objects

Let's say I write a class called Person


class Person:
  def __init__(self, name, age, job):
    self.name = name
    self.age = age
    self.job = job

  def work(self):
    print(self.name, 'is working...')

pickle can of course write, not only to the class itself, but to one instance of it.


#  Store the instance in a variable or, of course, in a file 
a_person = Person('abc', 22, 'waiter')
person_abc = pickle.dumps(a_person)
p = pickle.loads(person_abc)
p.work()
#  Store the class itself in a variable, loads Returns the class itself, not its 1 An instance 
class_Person = pickle.dumps(Person)
Person = pickle.loads(class_Person)
p = Person('Bob', 23, 'Student')
p.work()

#  The following example demonstrates storing a class in a file 
#  serialization 
with open('person.pkl', 'wb') as f:
  pickle.dump(Person, f)
#  deserialization 
with open('person.pkl', 'rb') as f:
  Person = pickle.load(f)
  aa = Person('gg', 23, '6')
  aa.work()

json module

pickle makes it easy to serialize all objects. However, json is a more standard format that is more readable (pickle is base 2 data) and cross-platform. It's a good choice.

The four function names used by json and pickle1.

Serialized as a string


dic = {'age': 23, 'job': 'student'}
dic_str = json.dumps(dic)
print(type(dic_str), dic_str)
# out: <class 'str'> {"age": 23, "job": "student"}

dic_obj = json.loads(dic_str)
print(type(dic_obj), dic_obj)
# out: <class 'dict'> {'age': 23, 'job': 'student'}

As you can see, the dumps function converts the object to a string. The loads function restores it to a dictionary.

Store as an json file

It can also be stored in an json file


dic = {'age': 23, 'job': 'student'}
with open('abc.json', 'w', encoding='utf-8') as f:
  json.dump(dic, f)

with open('abc.json', encoding='utf-8') as f:
  obj = json.load(f)
  print(obj)

Store custom objects

Again, the Person object above. An error will be reported if serialized directly


aa = Person('Bob', 23, 'Student')
with open('abc.json', 'w', encoding='utf-8') as f:
  json.dump(aa, f) #  An error 

Object of 'Person' is not JSON serializable At this point, the dump function can pass 1 argument to default, this parameter accepts 1 function, this function can convert the object to dictionary.

I'll just write 1


def person2dict(person):
  return {'name': person.name,
      'age': person.age,
      'job': person.job}

This returns a dictionary, and the object instance has a way to simplify this process. Call the instance of succes 90en__ directly. For example,


print(aa.__dict) # {'name': 'Bob', 'age': 23, 'job': 'Student'}

It's very convenient.

At the same time when reading load out is a dictionary, then back to the object can be, also need a parameter object_hook, this parameter receives a function, used to turn the dictionary into an object.


obj = pickle.loads(byte_data)
print(obj)
0

So the complete program should be written like this


obj = pickle.loads(byte_data)
print(obj)
1

With each ___ 105EN__ instead of the person2dict function, simplify with the lambda function.


obj = pickle.loads(byte_data)
print(obj)
2

This is storing to a file, and storing to a variable is a similar operation.

But from what I've learned so far, I don't know how to serialize our custom class itself using json as easily as pickle1, perhaps using some other extension function. We'll use it later.

shelve module

There is also a module, less commonly used, usually 1 open. shelve stores data as key-value pairs.


with shelve.open('aa') as f:
  f['person'] = {'age': 23, 'job': 'student'}
  f['person']['age'] = 44 #  This is trying to change the old age 23
  f['numbers'] = [i for i in range(10)]

with shelve.open('aa') as f:
  person = f['person']
  print(person) # {'age': 23, 'job': 'student'}
  nums = f['numbers']
  print(nums) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Without suffixes, windows generates aa. bak, ES129en. dat, aa. dir3 (a bit much). bak and dir files are viewable (they look like two files with one content) and generate such data in the following example.


obj = pickle.loads(byte_data)
print(obj)
4

Allowed to write back -writeback

One detail, when we read person, we found that age is still 23 years old, so f['person']['age'] = 44 does not become 44. Let me write it this way


obj = pickle.loads(byte_data)
print(obj)
5

This is equivalent to being assigned twice, and you can change the value in this way.

By default f['person'] will not update the stored value, that is, updates are not written back to the file, even after the file has been close. If so, add a parameter to the open function writeback=True. Run it again and see if the age has changed.

Writes a custom object

The Person object above is still used


obj = pickle.loads(byte_data)
print(obj)
6

The above example shows that shelve can also serialize the class itself. Serialization instances certainly can.


obj = pickle.loads(byte_data)
print(obj)
7

Note that since we are using with open to open, there is no need to write close, this module has the close function, if not the with method to open 1, remember active close.


Related articles: