""" """ __author__on__ = 'shaozhiqi 2019/9/24' # !/usr/bin/env python3 # -*- coding: utf-8 -*- # 在程序運行的過程中,所有的變量都是在內存中,比如,定義一個dict: d = dict(name='Bob', age=20, score=88) # 我們把變量從內存中變成可存儲或傳輸的過程稱之為**序列化**,在Python中叫pickling # 序列化之后,就可以把序列化后的內容寫入磁盤,或者通過網絡傳輸到別的機器上。 # 反過來,把變量內容從序列化的對象重新讀到內存里稱之為反序列化,即unpickling。 # Python提供了pickle模塊來實現序列化。 import pickle d = dict(name='Bob', age=20, score=88) pickle.dumps(d) # pickle.dumps()方法把任意對象序列化成一個bytes,然后,就可以把這個bytes寫入文件。 # 或者用另一個方法pickle.dump()直接把對象序列化后寫入一個file-like Object: f = open('dump.txt', 'wb') pickle.dump(d, f) f.close() # 看看寫入的dump.txt文件,一堆亂七八糟的內容,這些都是Python保存的對象內部信息。如下: # �}q (X nameqX BobqX ageqKX scoreqKXu. # -----------------------------------pickle反序列化------------------------------------ # 當我們要把對象從磁盤讀到內存時,可以先把內容讀到一個bytes, # 然后用pickle.loads()方法反序列化出對象,也可以直接用pickle.load()方法從一個file-like Object中直接反序列化出對象。 # 我們打開另一個Python命令行來反序列化剛才保存的對象: f = open('dump.txt', 'rb') d = pickle.load(f) f.close() print(d) # {'name': 'Bob', 'age': 20, 'score': 88} # 當然,這個變量和原來的變量是完全不相干的對象,它們只是內容相同而已。 # # Pickle的問題和所有其他編程語言特有的序列化問題一樣,就是它只能用於Python,並且可能不同版本的Python彼此都不兼容, # 因此,只能用Pickle保存那些不重要的數據,不能成功地反序列化也沒關系。 # ------------------------------------------json---------------------------------- # 如果我們要在不同的編程語言之間傳遞對象,就必須把對象序列化為標准格式, # 比如XML,但更好的方法是序列化為JSON,因為JSON表示出來就是一個字符串, # 可以被所有語言讀取,也可以方便地存儲到磁盤或者通過網絡傳輸。 # JSON不僅是標准格式,並且比XML更快,而且可以直接在Web頁面中讀取,非常方便。 # JSON類型 Python類型 # {} dict # [] list # "string" str # 1234.56 int或float # true/false True/False # null None # -----------------Python對象->JSON-------------------------------------------- import json d = dict(name='Bob', age=20, score=88) json_d = json.dumps(d) print(json_d) # {"name": "Bob", "age": 20, "score": 88} # dumps()方法返回一個str,內容就是標准的JSON。類似的,dump()方法可以直接把JSON寫入一個file-like Object。 # 要把JSON反序列化為Python對象,用loads()或者對應的load()方法,前者把JSON的字符串反序列化, # 后者從file-like Object中讀取字符串並反序列化: json_str = '{"age": 20, "score": 88, "name": "Bob"}' dictvlaue = json.loads(json_str) print(dictvlaue) print(type(dictvlaue)) # <class 'dict'> # 可以看到轉化為了dict類型 # ---------------------------------------------------------------------------------- # Python的dict對象可以直接序列化為JSON的{}, # 不過,很多時候,我們更喜歡用class表示對象,比如定義Student類,然后序列化: import json class Student(object): def __init__(self, name, age, score): self.name = name self.age = age self.score = score s = Student('Bob', 20, 88) # print(json.dumps(s)) # TypeError: Object of type Student is not JSON serializable # 錯誤的原因是Student對象不是一個可序列化為JSON的對象。 # 可選參數default就是把任意一個對象變成一個可序列為JSON的對象,我們只需要為Student專門寫一個轉換函數,再把函數傳進去即可: def student2dict(std): return { 'name': std.name, 'age': std.age, 'score': std.score } # 這樣,Student實例首先被student2dict() # 函數轉換成dict,然后再被順利序列化為JSON: print(json.dumps(s, default=student2dict)) # {"name": "Bob", "age": 20, "score": 88} # 那么問題來了,難道我們每轉化一個類為json都需要為其寫一個轉化函數嗎? # 因為通常class的實例都有一個__dict__屬性,它就是一個dict,用來存儲實例變量。 # 也有少數例外,比如定義了__slots__的class。 print('student:', json.dumps(s, default=lambda obj: obj.__dict__)) # student: {"name": "Bob", "age": 20, "score": 88} # 同樣的道理,如果我們要把JSON反序列化為一個Student對象實例, # loads()方法首先轉換出一個dict對象,然后,我們傳入的object_hook函數負責把dict轉換為Student實例: def dict2student(d): return Student(d['name'], d['age'], d['score']) json_str = '{"age": 20, "score": 88, "name": "Bob"}' student2 = json.loads(json_str, object_hook=dict2student) print('json-student:', student2.name) # json-student: Bob