φυβλαςのβλογ
phyblas的博客



การบันทึกและอ่านออบเจ็กต์ใน python ด้วย pickle
เขียนเมื่อ 2019/04/21 15:14
ปกติแล้วออบเจ็กต์หรือตัวแปรในไพธอนนั้นพอจบโปรแกรมก็จะถูกลบหายไป ไม่สามารถนำมาใช้ต่อได้ในโปรแกรมอื่น

เพื่อให้ออบเจ็กต์เดิมสามารถนำมาใช้ในโปรแกรมอื่นได้อาจต้องบันทึกข้อมูลในออบเจ็กต์ไว้แล้วดึงมาใช้ในโปรแกรมอื่น

สำหรับในไพธอนมีคำมอดูลที่เตรียมไว้สำหรับบันทึกข้อมูลออบเจ็กต์ลงเครื่องแล้วดึงมาใช้ใหม่ นั่นคือมอดูล 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 จะบันทึกไว้ว่าออบเจ็กต์นั้นเป็นออบเจ็กต์ของคลาสไหนในมอดูลไหน ดังนั้นถ้าหากว่าคลาสนั้นถูกนิยามในโปรแกรมหลัก มันก็จะไปหาคลาสชื่อนั้นในโปรแกรมนั้นเอง



อ้างอิง


-----------------------------------------

囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧

ดูสถิติของหน้านี้

หมวดหมู่

-- คอมพิวเตอร์ >> เขียนโปรแกรม >> python

ไม่อนุญาตให้นำเนื้อหาของบทความไปลงที่อื่นโดยไม่ได้ขออนุญาตโดยเด็ดขาด หากต้องการนำบางส่วนไปลงสามารถทำได้โดยต้องไม่ใช่การก๊อปแปะแต่ให้เปลี่ยนคำพูดเป็นของตัวเอง หรือไม่ก็เขียนในลักษณะการยกข้อความอ้างอิง และไม่ว่ากรณีไหนก็ตาม ต้องให้เครดิตพร้อมใส่ลิงก์ของทุกบทความที่มีการใช้เนื้อหาเสมอ

目录

从日本来的名言
python
-- numpy
-- matplotlib

-- pandas
-- pytorch
maya
机器学习
-- โครงข่าย
     ประสาทเทียม
javascript
与日本相关的日记
与中国相关的日记
-- 与北京相关的日记
与台湾相关的日记
与北欧相关的日记
与其他国家相关的日记
qiita
其他日志

按类别分日志



ติดตามอัปเดตของบล็อกได้ที่แฟนเพจ

  查看日志

  推荐日志

เรียนรู้วิธีการใช้ regular expression (regex)
หลักการเขียนทับศัพท์ภาษาจีนกวางตุ้ง
การใช้ unix shell เบื้องต้น ใน linux และ mac
หลักการเขียนทับศัพท์ภาษาจีนกลาง
g ในภาษาญี่ปุ่นออกเสียง "ก" หรือ "ง" กันแน่
ทำความรู้จักกับปัญญาประดิษฐ์และการเรียนรู้ของเครื่อง
ค้นพบระบบดาวเคราะห์ ๘ ดวง เบื้องหลังความสำเร็จคือปัญญาประดิษฐ์ (AI)
หอดูดาวโบราณปักกิ่ง ตอนที่ ๑: แท่นสังเกตการณ์และสวนดอกไม้
พิพิธภัณฑ์สถาปัตยกรรมโบราณปักกิ่ง
เที่ยวเมืองตานตง ล่องเรือในน่านน้ำเกาหลีเหนือ
บันทึกการเที่ยวสวีเดน 1-12 พ.ค. 2014
แนะนำองค์การวิจัยและพัฒนาการสำรวจอวกาศญี่ปุ่น (JAXA)
เล่าประสบการณ์ค่ายอบรมวิชาการทางดาราศาสตร์โดยโซวเคนได 10 - 16 พ.ย. 2013
ตระเวนเที่ยวตามรอยฉากของอนิเมะในญี่ปุ่น
เที่ยวชมหอดูดาวที่ฐานสังเกตการณ์ซิงหลง
บันทึกการเที่ยวญี่ปุ่นครั้งแรกในชีวิต - ทุกอย่างเริ่มต้นที่สนามบินนานาชาติคันไซ
หลักการเขียนทับศัพท์ภาษาญี่ปุ่น
ทำไมจึงไม่ควรเขียนวรรณยุกต์เวลาทับศัพท์ภาษาต่างประเทศ
ทำไมถึงอยากมาเรียนต่อนอก
เหตุผลอะไรที่ต้องใช้ภาษาวิบัติ?