Python 好用套件介紹 - cloudpickle (pickle 模組的鋼鐵裝)

Posted on  Sep 3, 2023  in  Python 模組/套件推薦 , Python 程式設計 - 中階  by  Amo Chen  ‐ 2 min read

你有沒有遇過某些資料或類別 pickle 之後,之後要 unpickle 時出現 AttributeError 的情況,例如:

AttributeError: Can't get attribute 'A' on <module '__main__' (built-in)>

這是由於 pickle 使用的是 serialization by reference 技術,所以某些資料或類別它不會放到序列化的結果,因此這種問題可以試看看用 cloudpickle 解決。

一起看看 cloudpickle 與 pickle 模組之間的差異,以及它如何能解決你的問題吧!

本文環境

$ pip install cloudpickle

cloudpickle 簡介

cloudpickle 是 Python pickle 模組的擴充,可以將原本 pickle 無法序列化(serialize)的 lambda, function 等給序列化,因爲 pickle 模組是 serialization by reference, 簡單來說就是告訴 Python 這個序列化後的東西有用到什麼 class, function 而已,沒有把這些 class 與 function 一併序列化,所以 A 機器序列化的結果,丟到 B 機器執行會有問題,因為沒有當初那些 class 或 function 。

例如 A 機器序列化 class A :

>>> class A:
...     pass
...
>>> pickle.dumps(A)
b'\x80\x04\x95\x12\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\x01A\x94\x93\x94.'

接著,丟到 B 機器 unpicklize:

>>> pickle.loads(b'\x80\x04\x95\x12\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\x01A\x94\x93\x94.')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: Can't get attribute 'A' on <module '__main__' (built-in)>

但如果改成用 cloudpickle 就不會這樣了!

A 機器序列化 class A , 此處可以看到序列化的結果比較長,這是因為 class A 的定義也被序列化:

>>> import cloudpickle
>>> class A:
...     pass
...
>>> cloudpickle.dumps(A)
b'\x80\x05\x95\xee\x00\x00\x00\x00\x00\x00\x00\x8c\x17cloudpickle.cloudpickle\x94\x8c\x14_make_skeleton_class\x94\x93\x94(\x8c\x08builtins\x94\x8c\x04type\x94\x93\x94\x8c\x01A\x94h\x03\x8c\x06object\x94\x93\x94\x85\x94}\x94\x8c\n__module__\x94\x8c\x08__main__\x94s\x8c 8fbd6d3daf3e404691dcd99c7bc8829f\x94Nt\x94R\x94\x8c\x1ccloudpickle.cloudpickle_fast\x94\x8c\x0f_class_setstate\x94\x93\x94h\x0f}\x94(h\x0bh\x0c\x8c\x07__doc__\x94Nu}\x94\x86\x94\x86R0.'

B 機器 unpickle:

>>> import cloudpickle
>>> cloudpickle.loads(b'\x80\x05\x95\xee\x00\x00\x00\x00\x00\x00\x00\x8c\x17cloudpickle.cloudpickle\x94\x8c\x14_make_skeleton_class\x94\x93\x94(\x8c\x08builtins\x94\x8c\x04type\x94\x93\x94\x8c\x01A\x94h\x03\x8c\x06object\x94\x93\x94\x85\x94}\x94\x8c\n__module__\x94\x8c\x08__main__\x94s\x8c 8fbd6d3daf3e404691dcd99c7bc8829f\x94Nt\x94R\x94\x8c\x1ccloudpickle.cloudpickle_fast\x94\x8c\x0f_class_setstate\x94\x93\x94h\x0f}\x94(h\x0bh\x0c\x8c\x07__doc__\x94Nu}\x94\x86\x94\x86R0.')
<class '__main__.A'>

一點問題也沒有!妥妥的!

Serialization by Value

由於 cloudpickle 用的是 serialization by value, 用到的 function, class 等定義都會一併序列化,所以不會有 reference 找不到的問題,但是 import 的部分不會做序列化,因為如果連 import 的模組都要序列化的話,就會跟粽子一樣一大串,恐怕失去效率。

這種序列化技術相當適合類似 Spark 這種叢集運算(cluster computing), 只要將程式序列化之後,就可以透過網路傳輸到各個節點進行運算,所以你不用為了算數據,每個節點都需要部署相同的程式,只要確保相同的執行環境(Python 版本、套件版本等等)就好,剩下的交給 cloudpickle 這類技術。

噢,沒錯, PySpark 內部就是使用 cloudpickle XD

最後宣導一個資安觀念,千萬別隨意執行未知來源的 pickle data

以上!

Happy Coding!

References

https://github.com/cloudpipe/cloudpickle

pickle — Python object serialization

對抗久坐職業傷害

研究指出每天增加 2 小時坐著的時間,會增加大腸癌、心臟疾病、肺癌的風險,也造成肩頸、腰背疼痛等常見問題。

然而對抗這些問題,卻只需要工作時定期休息跟伸展身體即可!

你想輕鬆改變現狀嗎?試試看我們的 PomodoRoll 番茄鐘吧! PomodoRoll 番茄鐘會根據你所設定的專注時間,定期建議你 1 項辦公族適用的伸展運動,幫助你打敗久坐所帶來的傷害!

贊助我們的創作

看完這篇文章了嗎? 休息一下,喝杯咖啡吧!

如果你覺得 MyApollo 有讓你獲得實用的資訊,希望能看到更多的技術分享,邀請你贊助我們一杯咖啡,讓我們有更多的動力與精力繼續提供高品質的文章,感謝你的支持!