Python: Serializacja i deserializacja
Moduły pickle oraz json
Przygotowanie
- Uczeń posiada interpreter języka Python
- Utwórz katalog do pracy, np.
20-py-ser-des
Wersje protokołów modułu pickle
wersja 0 protokołu
wersja 1 protokołu
wersja 2 protokołu
wersja 3 protokołu - dodana w
Python 3.0
wspiera obiekty bajtowe; nie działa dlaPython 2.x
wersja 4 protokołu - dodana w
Python 3.4
(min. obsługa duzych obieków, więcej ich rodzajów oraz optymalizacje formatów). Domyślny od wersjiPython 3.8
wersja 5 protokołu - dodana w
Python 3.8
Tabela porównawcza
JSON | Pickle |
---|---|
tekstowy format serializacji (unicode, utf-8) | binarny format serializacji |
czytelny dla człowieka | nieczytelny dla człowieka |
interoperabilny poza ekosystemem Python'a | specyficzny dla języka Python |
domyślnie reprezentuje podzbiór wbudowanych typów Pythona, bez obsługi klas | pickle reprezentuje obszerny zbiór typów Python'a (wiele typów automatycznie, a złożone poprzez tzw. introspekcję) |
deserializacja niezaufanych ciągów JSON nie stanowi zagrożenia | deserializacja niezaufanych ciągów JSON jest ryzykiem uruchomienia niebezpiecznego kodu |
Aby móc serializować i deserializować dane wymagany jest import odpowiednich pakietów
import pickle
dla formatu natywnego języka Pythonimport json
dla formatu JSON (JavaScript Object Notation)
Podstawowe metody modułu Pickle
pickle.dumps( dane_Python )
- konwertuje dane natywne języka Python do formatu binarnegopickle.Pickler( plik ).dump( dane_Python )
- j/w, lecz zapisuje dane do plikupickle.dump( dane_Python, plik )
- j/wpickle.loads( dane_zserializowane )
odczytuje zserializowane dane do formatu obiektu języka Pythonpickle.Unpickler( plik ).load()
- j/w, lecz odczytuje dane z plikupickle.load( plik )
- j/w
Podstawowe metody modułu json
json.dumps( dane_Python )
- konwertuje dane natywne języka Python do formatu JSONjson.loads( dane_JSON )
- odczytuje zserializowane dane formatu JSON do formatu obiektu języka Pythonjson.JSONEncoder().encode( dane_JSON )
- j/w
Moduł Pickle
Typy danych jakie można zserializować
None
,True
orazFalse
integer, float, complex number
string, byte, bytearray
krotki (tuple), listy, zbiory (set), słowniki (dict) z obiektami "pickle-able"
funkcje zdefiniowane na najwyższym poziomie modułu (
def
, bezlambda
)wbudowane funkcje modułu zdefiniowane na najwyższym poziomie modułu
klasy zdefiniowane na najwyższym poziomie modułu
instancje, których
__dict__
lub rezultat wywołania__getstate__()
jest "pickle-able"
Przykład kodu App1.py
obsługi modułu pickle
import io
import pickle
import copy
class Cos:
attr = 'Atrybut klasy'
print("Klasa Cos z instancji cos:")
print(Cos)
print(Cos.attr)
print("")
# piklujemy klasę
pkcos = pickle.dumps(Cos)
# efekt
print(pkcos)
print("")
# odpiklowujemy
thing = pickle.loads( pkcos )
# efekt
print("Klasa Cos z instancji thing:")
print(thing)
print(thing.attr)
print("")
# zmiany wartości atrybutów
print("Atrybuty przed zmianą:")
cos = Cos
print("Cos = "+cos.attr)
print("Thing= "+thing.attr)
cos.attr = "Jestem Coś"
thing.attr = "I am a Thing"
print("")
print("Atrybuty po zmianie:")
print("Cos = "+cos.attr)
print("Thing= "+thing.attr)
Przykład kodu App2.py
obsługi modułu json
import json
import copy
#jsonStr = "{ course:'ad', unit:'3pt4', lesson:'8', dateAt:'2022-03-29', topic:'Serializacja i deserializacja' }"
jsonStr = '{ "course":"ad", "unit":"3pt4", "lesson":"20", "dateAt":"2022-03-29", "topic":"Serializacja i deserializacja" }'
print("Ciąg string z danymi JSON")
print(jsonStr)
print("")
print("String z danymi JSON zdekodowany do...")
pyObj = json.loads(jsonStr)
print(pyObj)
print("")
print("Klucz=Wartość")
print("Kurs: "+pyObj['course'])
print("Klasa: "+pyObj['unit'])
print("Lekcja: "+pyObj['lesson'])
print("Data: "+pyObj['dateAt'])
print("Temat: "+pyObj['topic'])
print("")
print("Zduplikowanie słownika (dict)")
lsn = copy.deepcopy(pyObj) # duplikat, bez referencji
lsn['unit'] = '3pt5'
lsn['lesson'] = '34'
lsn['dateAt'] = '2022-04-04'
print(lsn)
print(pyObj)
print("")
print("Zakodowanie obiektu Python do stringa JSON")
jsonStr2 = json.dumps(lsn)
#jsonStr2 = json.JSONEncoder().encode(lsn)
print(jsonStr2)
#json.loads(json_file_1)
Przykład kodu App3.py
obsługi instancji klasy
import io
import pickle
class Client:
# podczas deserializacji metoda __init__ NIE jest wywoływana
# natomiast właściwości atrybutów są przywracane
def __init__(self, name):
self.ip = "192.168.0.1"
self.host = "teacherDesk"
self.name = name
print("Jestem initem "+self.host+" dla "+self.name)
def save(obj):
return (obj.__class__, obj.__dict__)
def load(cls, attr):
obj = cls.__new(cls)
obj.__dict__.update(attr)
return obj
c1 = Client("GP")
print(c1)
print("")
c2 = Client("RR")
print(c2)
print("")
# piklowanie instancji Client(GP)
c1p = pickle.dumps(c1)
print(c1p)
c1 = None # wyczyszczenie instancji Client(GP)
print(c1)
# odpiklowujemy zapamiętaną instancję Client(GP)
c1 = pickle.loads(c1p)
print(c1.host+" "+c1.name)
print(c1)
print("")
#c3 = Client("BL")
#pkFile = 'tmp_pk'
#with open(pkFile, "wb") as fp:
## c3p = pickle.Pickler(fp).dump(c3)
# c3p = pickle.dump(c3, fp)
Przykład kodu Pack.py
obsługi zapisu do pliku oraz NotClient.py
do odczytu z pliku
Nie odnaleziono pliku!
Nie odnaleziono pliku!
Przykład kodu App4.py
Heelloo
Line no.2
Goodbye!
import io
import pickle
class TextReader:
"""Print and number lines in a text file."""
def __init__(self, filename):
self.filename = filename
self.file = open(filename)
self.lineno = 0
def readline(self):
self.lineno += 1
line = self.file.readline()
if not line:
return None
if line.endswith('\n'):
line = line[:-1]
return "%i: %s" % (self.lineno, line)
def __getstate__(self):
# Copy the object's state from self.__dict__ which contains
# all our instance attributes. Always use the dict.copy()
# method to avoid modifying the original state.
state = self.__dict__.copy()
# Remove the unpicklable entries.
del state['file']
return state
def __setstate__(self, state):
# Restore instance attributes (i.e., filename and lineno).
self.__dict__.update(state)
# Restore the previously opened file's state. To do so, we need to
# reopen it and read from it until the line count is restored.
file = open(self.filename)
for _ in range(self.lineno):
file.readline()
# Finally, save the file.
self.file = file
reader = TextReader("hello.txt")
print(reader.readline())
print(reader.readline())
new_reader = pickle.loads(pickle.dumps(reader))
print(new_reader.readline())