1. 程式人生 > >python: 序列化/反序列化及物件的深拷貝/淺拷貝

python: 序列化/反序列化及物件的深拷貝/淺拷貝

一、序列化/反序列化

python中內建了很多序列化/反序列化的方式,最常用的有json、pickle、marshal這三種,示例用法如下:

import json
import pickle
import marshal

author1 = {"name": "菩提樹下的楊過", "blog": "http://yjmyzz.cnblogs.com/", "title": "架構師", "pets": ["dog", "cat"]}

# json序列化
json_str = json.dumps(author1)
print("json=>\n", json_str)

# json字串反序列化
author2 = json.loads(json_str)

# pickle序列化
pickle_str = pickle.dumps(author1)
print("pickle=>\n", pickle_str)

# pickle字串反序列化
author3 = pickle.loads(pickle_str)

# marshal序列化
marshal_str = marshal.dumps(author1)
print("marshal=>\n", marshal_str)

# marshal反序列化
author4 = marshal.loads(marshal_str)

print("\n",
      id(author1), "\n",
      id(author2), "\n",
      id(author3), "\n",
      id(author4), "\n",
      author1, "\n",
      author2, "\n",
      author3, "\n",
      author4)

with open("json.txt", "w") as file1:
    json.dump(author1, file1)

with open("pickle.txt", "wb") as file2:
    pickle.dump(author1, file2)

with open("marshal.txt", "wb") as file3:
    marshal.dump(author1, file3)  

輸出:

json=>
 {"name": "\u83e9\u63d0\u6811\u4e0b\u7684\u6768\u8fc7", "blog": "http://yjmyzz.cnblogs.com/", "title": "\u67b6\u6784\u5e08", "pets": ["dog", "cat"]}
pickle=>
 b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x15\x00\x00\x00\xe8\x8f\xa9\xe6\x8f\x90\xe6\xa0\x91\xe4\xb8\x8b\xe7\x9a\x84\xe6\x9d\xa8\xe8\xbf\x87q\x02X\x04\x00\x00\x00blogq\x03X\x1a\x00\x00\x00http://yjmyzz.cnblogs.com/q\x04X\x05\x00\x00\x00titleq\x05X\t\x00\x00\x00\xe6\x9e\xb6\xe6\x9e\x84\xe5\xb8\x88q\x06X\x04\x00\x00\x00petsq\x07]q\x08(X\x03\x00\x00\x00dogq\tX\x03\x00\x00\x00catq\neu.'
marshal=>
 b'\xfb\xda\x04name\xf5\x15\x00\x00\x00\xe8\x8f\xa9\xe6\x8f\x90\xe6\xa0\x91\xe4\xb8\x8b\xe7\x9a\x84\xe6\x9d\xa8\xe8\xbf\x87\xda\x04blog\xfa\x1ahttp://yjmyzz.cnblogs.com/\xda\x05title\xf5\t\x00\x00\x00\xe6\x9e\xb6\xe6\x9e\x84\xe5\xb8\x88\xda\x04pets[\x02\x00\x00\x00\xda\x03dog\xda\x03cat0'

 4307564944 
 4309277360 
 4307565016 
 4309277432 
 {'name': '菩提樹下的楊過', 'blog': 'http://yjmyzz.cnblogs.com/', 'title': '架構師', 'pets': ['dog', 'cat']} 
 {'name': '菩提樹下的楊過', 'blog': 'http://yjmyzz.cnblogs.com/', 'title': '架構師', 'pets': ['dog', 'cat']} 
 {'name': '菩提樹下的楊過', 'blog': 'http://yjmyzz.cnblogs.com/', 'title': '架構師', 'pets': ['dog', 'cat']} 
 {'name': '菩提樹下的楊過', 'blog': 'http://yjmyzz.cnblogs.com/', 'title': '架構師', 'pets': ['dog', 'cat']}

注:api的方法名還是很好記的,dump/dumps意為“倒垃圾”,把物件向xxx裡一倒,就算序列化完成了。反之load/loads即從字串或檔案中裝載(還原)物件。特別要值得一提的是:pickle、marshal存在安全問題,如果裝載的字串或檔案裡,包含有精心設計的惡意程式碼,會讓惡意程式碼執行(關於反序列化的漏洞,大家可以上網查一下,有很多類似的介紹)。另外從序列化後的字串大小來看,預設情況下,就本示例而言,json序列化後的字串長度最小,so,綜合來看,推薦同學們使用json序列化/反序列化

二、深拷貝、淺拷貝

import copy

list_1 = [1, 2, 3, [4, 5]]

list_2 = copy.copy(list_1)  # 淺拷貝

list_3 = copy.deepcopy(list_1)  # 深拷貝

list_2[3][0] = 99

print("\n", list_1, "\n", list_2, "\n", list_3)

list_3[3][1] = 100

print("\n", list_1, "\n", list_2, "\n", list_3)

  輸出:

 [1, 2, 3, [99, 5]] 
 [1, 2, 3, [99, 5]] 
 [1, 2, 3, [4, 5]]

 [1, 2, 3, [99, 5]] 
 [1, 2, 3, [99, 5]] 
 [1, 2, 3, [4, 100]]

  當一個物件裡的子元素本身也是複雜元素時,淺拷貝不會為這種複雜的子元素生成全新的例項,但深拷貝可以。下面的記憶體分佈示意圖有助於大家理解:

list_2是list_1淺拷貝生成的物件,對於第4個元素,都是指向同一個列表[4,5],所以list_2修改了[4,5]中的第1個元素為99後,list_1也受到影響。list_3則是深拷貝的結果,所有元素都是獨立的新例項,因此修改list_3裡的任何元素,都不會影響list_1、list_2

參考文件: