Python中如何序列化對(duì)象?序列化時(shí)如何避免循環(huán)引用?

python中序列化對(duì)象的方法主要有pickle和json,針對(duì)安全性、性能、兼容性和可讀性進(jìn)行選擇。1.pickle模塊支持復(fù)雜對(duì)象和自定義類的序列化,但存在安全風(fēng)險(xiǎn),尤其在反序列化不可信數(shù)據(jù)時(shí);2.json模塊更安全,但僅限于內(nèi)置數(shù)據(jù)類型的序列化,適用于跨語言兼容和文本可讀性要求高的場景;3.處理循環(huán)引用時(shí),pickle默認(rèn)跟蹤對(duì)象避免重復(fù)序列化,但復(fù)雜情況下建議手動(dòng)打破循環(huán),如將引用設(shè)為none后再恢復(fù);4.自定義序列化可通過__getstate__和__setstate__方法實(shí)現(xiàn),靈活控制屬性的保存與恢復(fù)過程。綜合考慮需求后合理選用方法,若僅python內(nèi)部使用且追求性能可選pickle,否則優(yōu)先用json。

Python中如何序列化對(duì)象?序列化時(shí)如何避免循環(huán)引用?

Python中序列化對(duì)象,簡單說就是把對(duì)象變成字符串或者字節(jié)流,方便存儲(chǔ)或傳輸。避免循環(huán)引用,得用點(diǎn)技巧,不然會(huì)卡死。

Python中如何序列化對(duì)象?序列化時(shí)如何避免循環(huán)引用?

解決方案

Python提供了pickle模塊來做序列化,但pickle容易出安全問題,特別是反序列化不可信數(shù)據(jù)的時(shí)候。更安全的選擇是json,但json只能序列化Python內(nèi)置的一些類型,比如字典、列表、字符串、數(shù)字等。如果你的對(duì)象比較復(fù)雜,或者自定義的類,json就搞不定了。

Python中如何序列化對(duì)象?序列化時(shí)如何避免循環(huán)引用?

pickle的基本用法:

立即學(xué)習(xí)Python免費(fèi)學(xué)習(xí)筆記(深入)”;

Python中如何序列化對(duì)象?序列化時(shí)如何避免循環(huán)引用?

import pickle  class MyClass:     def __init__(self, data):         self.data = data  obj = MyClass(123)  # 序列化到文件 with open('my_object.pkl', 'wb') as f:     pickle.dump(obj, f)  # 從文件反序列化 with open('my_object.pkl', 'rb') as f:     loaded_obj = pickle.load(f)  print(loaded_obj.data) # 輸出: 123

避免循環(huán)引用,pickle其實(shí)自帶了處理機(jī)制。它會(huì)跟蹤已經(jīng)序列化的對(duì)象,如果遇到重復(fù)的對(duì)象,就不會(huì)再次序列化,而是保存一個(gè)引用。但如果循環(huán)引用過于復(fù)雜,可能會(huì)導(dǎo)致性能問題。

一個(gè)更靠譜的方法是手動(dòng)打破循環(huán)引用。在序列化之前,把循環(huán)引用的地方設(shè)置為None,序列化之后再恢復(fù)。

import pickle  class Node:     def __init__(self, name):         self.name = name         self.parent = None         self.children = []      def add_child(self, child):         self.children.append(child)         child.parent = self  node1 = Node("Node 1") node2 = Node("Node 2") node3 = Node("Node 3")  node1.add_child(node2) node2.add_child(node3) node3.add_child(node1)  # 循環(huán)引用  # 序列化前打破循環(huán)引用 node3.parent = None  # 序列化 serialized_data = pickle.dumps(node1)  # 反序列化 loaded_node1 = pickle.loads(serialized_data)  # 恢復(fù)循環(huán)引用(可選,如果需要的話) # loaded_node3 = loaded_node1.children[0].children[0] # loaded_node3.parent = loaded_node1

如何選擇合適的序列化方法?

選擇序列化方法,要考慮幾個(gè)因素:安全性、性能、兼容性和可讀性。

  • 安全性: 如果要序列化的數(shù)據(jù)來自不可信的來源,千萬別用pickle。json更安全,但只能序列化簡單的數(shù)據(jù)類型。
  • 性能: pickle通常比json快,但如果對(duì)象結(jié)構(gòu)復(fù)雜,json可能更有效率。
  • 兼容性: json是一種通用的數(shù)據(jù)格式,在不同的編程語言和平臺(tái)之間都有很好的兼容性。pickle只能在Python中使用。
  • 可讀性: json是文本格式,可讀性好。pickle是二進(jìn)制格式,可讀性差。

如果對(duì)性能要求不高,而且數(shù)據(jù)結(jié)構(gòu)簡單,json是首選。如果性能是關(guān)鍵,而且數(shù)據(jù)只在Python中使用,可以考慮pickle,但一定要注意安全問題。

如何自定義序列化和反序列化過程?

有時(shí)候,默認(rèn)的序列化方式可能不滿足需求。比如,你可能想忽略某些屬性,或者對(duì)某些屬性進(jìn)行特殊處理。

pickle提供了__getstate__和__setstate__兩個(gè)方法,可以讓你自定義序列化和反序列化的過程。

  • __getstate__:在序列化之前被調(diào)用,返回一個(gè)對(duì)象的狀態(tài)。你可以選擇返回哪些屬性,或者對(duì)屬性進(jìn)行修改。
  • __setstate__:在反序列化之后被調(diào)用,接收__getstate__返回的狀態(tài)。你可以用這個(gè)狀態(tài)來恢復(fù)對(duì)象。
import pickle  class MyClass:     def __init__(self, a, b, c):         self.a = a         self.b = b         self.c = c      def __getstate__(self):         # 只序列化a和b         return {'a': self.a, 'b': self.b}      def __setstate__(self, state):         # 恢復(fù)a和b,c設(shè)置為默認(rèn)值         self.a = state.get('a', 0)         self.b = state.get('b', 0)         self.c = -1  # 默認(rèn)值  obj = MyClass(1, 2, 3)  # 序列化 serialized_data = pickle.dumps(obj)  # 反序列化 loaded_obj = pickle.loads(serialized_data)  print(loaded_obj.a, loaded_obj.b, loaded_obj.c) # 輸出: 1 2 -1

這樣,你就可以靈活地控制對(duì)象的序列化和反序列化過程,滿足各種特殊需求。

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點(diǎn)贊15 分享