ปกติแล้วออบเจ็กต์หรือตัวแปรในไพธอนนั้นพอจบโปรแกรมก็จะถูกลบหายไป ไม่สามารถนำมาใช้ต่อได้ในโปรแกรมอื่น
เพื่อให้ออบเจ็กต์เดิมสามารถนำมาใช้ในโปรแกรมอื่นได้อาจต้องบันทึกข้อมูลในออบเจ็กต์ไว้แล้วดึงมาใช้ในโปรแกรมอื่น
สำหรับในไพธอนมีคำมอดูลที่เตรียมไว้สำหรับบันทึกข้อมูลออบเจ็กต์ลงเครื่องแล้วดึงมาใช้ใหม่ นั่นคือมอดูล pickle
pickle นั้นจริงๆมีความหมายว่าผักดอง ในที่นี้น่าจะหมายถึงว่าการเก็บออบเจ็กต์ในไพธอนไว้ในเครื่องก็เหมือนเป็นการเอาผักไปดองไว้เพื่อจะมากินภายหลัง
ออบเจ็กต์ที่จะบันทึกด้วย pickle นั้นจะเป็นออบเจ็กต์พื้นฐานในไพธอนเช่น list, tuple, dict หรือตัวแปรง่ายๆอย่างพวกจำนวนตัวเลขหรือสายอักขระก็ได้ นอกจากนี้ยังบันทึกออบเจ็กต์จากมอดูลเสริมหรือออบเจ็กต์ที่ผู้เขียนนิยามขึ้นมาเองได้ด้วย
ตัวอย่างเช่น ลองสร้างคลาสอะไรขึ้นมาสักอย่าง เช่นคลาสสำหรับเก็บข้อมูลของตู้เย็นง่ายๆอันนึง บันทึกคลาสใส่ไฟล์ไว้ ตั้งชื่อเป็น tuyen.py
#tuyen.py
class Tuyen:
def __init__(self,yiho,khong):
self.yiho = yiho
self.khong = khong
def __str__(self):
return 'ตู้เย็นยี่ห้อ %s ใส่%s'%(self.yiho,'กับ'.join(self.khong))
(ภาพประกอบไม่มีความเกี่ยวข้องกับเนื้อหาแต่อย่างใด แต่เข้ากับอากาศร้อน)
จากนั้น import คลาส Tuyen นั้นมา สร้างออบเจ็กต์ขึ้นแล้วทำการบันทึกใส่ไฟล์โดยใช้คำสั่ง dump ของ pickle
from tuyen import Tuyen
import pickle
tuyen1 = Tuyen('hitachi',['ผักดอง','นมสด','เนื้อบด'])
f = open('tuyen1.pkl','wb')
pickle.dump(tuyen1,f)
f.close()
ขั้นตอนอาจดูแล้วมีความยุ่งยากเล็กน้อย คือต้องใช้คำสั่ง open เพื่อเปิดไฟล์มาด้วยโหมด 'wb' นั่นคือโหมดเขียนไฟล์ไบนารี
จากนั้นก็ใช้คำสั่ง pickle.dump กับไฟล์ที่เปิดขึ้นมา เสร็จแล้วก็ปิดไฟล์ไป
เท่านี้ก็จะได้ไฟล์ไบนารีที่เก็บข้อมูลของออบเจ็กต์มา โดยทั่วไปนิยมใช้สกุลเป็น .pkl หรือ .pickle
เนื่องจากเป็นไฟล์ไบนารี ดังนั้นจึงไม่สามารถเปิดขึ้นมาเพื่ออ่านได้โดยตรง แต่มีข้อดีคือประหยัดเนื้อที่ในการเก็บมากกว่าบันทึกเป็นไฟล์ตัวหนังสือ
จากนั้นในอีกโปรแกรมนึงก็แค่เปิดไฟล์ด้วยโหมด 'rb' คือโหมดอ่านไฟล์ไบนารี แล้วใช้คำสั่ง load เท่านี้ออบเจ็กต์ก็จะถูกดึงมาใช้ในโปรแกรมนี้ได้
import pickle
f = open('tuyen1.pkl','rb')
tuyen2 = pickle.load(f)
f.close()
print(tuyen2) # ได้ ตู้เย็นยี่ห้อ hitachi ใส่ผักดองกับนมสดกับเนื้อบด
เพื่อความสะดวกอาจสร้างเป็นฟังก์ชันไว้ใช้งานให้สั่งทีเดียวอ่านหรือเขียนไฟล์ได้เลย เช่นแบบนี้
def savepickle(obj,chue):
with open(chue,'wb') as f:
pickle.dump(obj,f)
def loadpickle(chue):
with open(chue,'rb') as f:
return pickle.load(f)
savepickle(tuyen1,'tuyen1.pkl') # บันทึก
tuyen3 = loadpickle('tuyen1.pkl') # เปิดอ่าน
นอกจากนี้ยังมีวิธีการเขียนอีกแบบ คือใช้ dumps กับ loads วิธีการคล้ายๆกันกับ dump และ load แต่จะต่างกันเล็กน้อย
หากเขียนฟังก์ชันสำหรับบันทึกและอ่านใหม่โดยใช้ dumps กับ loads อาจเขียนได้แบบนี้
def savepickle(obj,chue):
with open(chue,'wb') as f:
f.write(pickle.dumps(obj))
def loadpickle(chue):
with open(chue,'rb') as f:
return pickle.loads(f.read())
ไฟล์ที่บันทึกด้วย pickle นั้นมีไว้สำหรับใช้เปิดในไพธอนเท่านั้น เพราะเป็นออบเจ็กต์ของไพธอน จะนำไปใช้ในโปรแกรมภาษาอื่นก็ไม่ได้
และถ้าหากเป็นคลาสที่นิยามขึ้นเองภายในโปรแกรมนั้น ข้อมูลของคลาสของออบเจ็กต์นั้นไม่ได้ถูกเก็บลงในไฟล์ด้วย ดังนั้นต้องมีการนิยามคลาสนั้นขึ้นใหม่ก่อนด้วย ไม่เช่นนั้นจะอ่านออบเจ็กต์นั้นไม่ได้
หรือถ้าหากสิ่งที่บันทึกนั้นเป็นคลาสหรือออบเจ็กต์ที่นิยามในโปรแกรมนั้นๆ
เช่นลองนิยามฟังก์ชันขึ้นมาแล้วบันทึก
import pickle
def g(x):
return x+1
print(g(1)) # ได้ 2
with open('g.pkl','wb') as f:
pickle.dump(g,f)
จากนั้นลองเปิดไฟล์ขึ้นมาแบบนี้ ก็จะพบว่า error เพราะหา g ที่นิยามขึ้นในโปรแกรมหลักไม่เจอ
import pickle
with open('g.pkl','rb') as f:
h = pickle.load(f) # ได้ AttributeError: Can't get attribute 'g' on <module '__main__'>
แต่ถ้าหากเรานิยามฟังก์ชั้น g ขึ้นมาใหม่ในโปรแกรมด้วย แม้จะไม่เหมือนเดิมก็ตาม จะกลายเป็นว่าโหลดได้สำเร็จ แต่ออบเจ็กต์ที่ได้มานั้นก็จะเป็นฟังก์ชันใหม่นั้น
import pickle
def g(x):
return x+10
with open('g.pkl','rb') as f:
h = pickle.load(f)
print(h(1)) # ได้ 11
ดังนั้น ไม่ควรใช้ pickle เพื่อเก็บคลาสหรือฟังก์ชันที่นิยามภายในโปรแกรมนั้น หรือออบเจ็กต์ของคลาสที่นิยามในโปรแกรมนั้น แต่ให้ใช้กับออบเจ็กต์ของคลาสที่ import เข้ามาจากมอดูลหรือไฟล์อื่น ไฟล์ pickle จะบันทึกไว้ว่าออบเจ็กต์นั้นเป็นออบเจ็กต์ของคลาสไหนในมอดูลไหน ดังนั้นถ้าหากว่าคลาสนั้นถูกนิยามในโปรแกรมหลัก มันก็จะไปหาคลาสชื่อนั้นในโปรแกรมนั้นเอง
อ้างอิง