ฉันจะบันทึกและกู้คืนตัวแปรหลายตัวใน python ได้อย่างไร


106

ฉันต้องการบันทึกวัตถุประมาณหนึ่งโหลลงในไฟล์แล้วเรียกคืนในภายหลัง ฉันพยายามใช้ห่วงกับของดองและชั้นวาง แต่มันไม่ได้ผล

แก้ไข.
ออบเจ็กต์ทั้งหมดที่ฉันพยายามบันทึกอยู่ในคลาสเดียวกัน (ฉันควรจะพูดถึงสิ่งนี้ก่อนหน้านี้) และฉันไม่รู้ว่าฉันสามารถช่วยทั้งคลาสได้แบบนี้:

import pickle
def saveLoad(opt):
    global calc
    if opt == "save":
        f = file(filename, 'wb')
        pickle.dump(calc, f, 2)
        f.close
        print 'data saved'
    elif opt == "load":
        f = file(filename, 'rb')
        calc = pickle.load(f)
    else:
        print 'Invalid saveLoad option'

1
คุณบอกว่าคุณได้ลองเล่นวนซ้ำ โปรดโพสต์รหัสนั้นและทำไม "จึงไม่ทำงาน" (เช่นสิ่งที่เกิดขึ้นและสิ่งที่คุณต้องการให้เกิดขึ้น)
แบลร์

หากคุณใช้ Windows อย่าลืมเปิดไฟล์ในโหมดไบนารี
John La Rooy

@gnibbler: โหมดไบนารีจำเป็นสำหรับโปรโตคอลที่ไม่ใช่ค่าเริ่มต้นเท่านั้น ( docs.python.org/library/pickle.html#usage )
Eric O Lebigot

คำตอบ:


172

หากคุณต้องการบันทึกวัตถุหลายชิ้นคุณสามารถใส่ไว้ในรายการเดียวหรือทูเพิลตัวอย่างเช่น:

import pickle

# obj0, obj1, obj2 are created here...

# Saving the objects:
with open('objs.pkl', 'w') as f:  # Python 3: open(..., 'wb')
    pickle.dump([obj0, obj1, obj2], f)

# Getting back the objects:
with open('objs.pkl') as f:  # Python 3: open(..., 'rb')
    obj0, obj1, obj2 = pickle.load(f)

หากคุณมีข้อมูลจำนวนมากคุณสามารถลดขนาดไฟล์ได้โดยส่งprotocol=-1ไปที่dump(); pickleจากนั้นจะใช้โปรโตคอลที่ดีที่สุดที่มีอยู่แทนที่จะเป็นโปรโตคอลย้อนหลังที่เป็นค่าเริ่มต้น ในกรณีนี้ไฟล์จะต้องเปิดในโหมดไบนารี ( wbและrbตามลำดับ)

ควรใช้โหมดไบนารีกับ Python 3 ด้วยเนื่องจากโปรโตคอลเริ่มต้นจะสร้างข้อมูลไบนารี (เช่นไม่ใช่ข้อความ) (โหมดการเขียน'wb'และโหมดการอ่าน'rb')


12
ใน Python 3.5 ฉันต้องเปิดไฟล์ในโหมด "byte" เช่นwith open('objs.pickle', 'wb') as f:(สังเกตwb)
kbrose

สวัสดี @ เอริกอะไรคือสิ่งที่ต้องการwith open('objs.pkl') as f:เปรียบเทียบง่ายๆobj1, obj2 = pickle.load(open("objs.pkl","rb"))? มีความแตกต่างระหว่างสองสิ่งนี้หรือไม่?
balandongiv

ด้วยรูปแบบที่สองคุณไม่ต้องปิดไฟล์ นี่ไม่ถือเป็นแนวทางปฏิบัติที่ดีเนื่องจากจำนวนไฟล์ที่คุณสามารถเปิดแบบขนานได้นั้นมักจะถูก จำกัด โดยระบบปฏิบัติการ (ลองวนซ้ำที่เปิดไฟล์โดยไม่ต้องปิด!) ที่กล่าวว่าในทางปฏิบัติการไม่ปิดไฟล์มักจะใช้ได้ผลเมื่อคุณไม่ได้เปิดไฟล์จำนวนมาก
Eric O Lebigot

51

มีไลบรารีในตัวที่เรียกว่าpickle. การใช้pickleคุณสามารถถ่ายโอนวัตถุไปยังไฟล์และโหลดในภายหลัง

import pickle

f = open('store.pckl', 'wb')
pickle.dump(obj, f)
f.close()

f = open('store.pckl', 'rb')
obj = pickle.load(f)
f.close()

1
I Python 3.4 ใช้: f = open('store.pckl', 'wb')เพื่อเปิดไฟล์ที่จะเขียน อ้างถึงstackoverflow.com/questions/13906623/… และใช้ `f = open ('store.pckl', 'rb') เพื่อเปิดไฟล์ที่จะอ่าน อ้างถึงstackoverflow.com/questions/7031699/… .
user3731622

สิ่งนี้เฉพาะสำหรับ 3.4+ หรือไม่ ฉันเกือบจะโหวตคำตอบเพราะมันสร้างข้อผิดพลาดเมื่อคุณไม่ใช้ 'b'
Wilmer E. Henao

12

คุณควรดูที่โมดูลชั้นวางและของดอง หากคุณต้องการจัดเก็บข้อมูลจำนวนมากการใช้ฐานข้อมูลอาจดีกว่า


ฉันต้องการบันทึกออบเจ็กต์เดียวที่ล็อกอินเข้าสู่เซิร์ฟเวอร์คลาวด์เพื่อจัดการหากฉันเข้าสู่ระบบหลายครั้งในช่วงเวลาหนึ่งเซิร์ฟเวอร์จะปฏิเสธคำขอของฉัน การทิ้งวัตถุลงในไฟล์โดยใช้โมดูลดองอาจมีปัญหาด้านความปลอดภัยหรือไม่? ตัวอย่างเช่นหากมีคนได้รับวัตถุที่ทิ้งของฉันไปกว่าที่พวกเขาจะสามารถล็อกอินเข้าสู่ที่เก็บข้อมูลบนคลาวด์ของฉันได้โดยไม่ต้องใช้รหัสผ่าน
alper

5

อีกวิธีหนึ่งในการบันทึกตัวแปรหลายตัวลงในไฟล์ดองคือ:

import pickle

a = 3; b = [11,223,435];
pickle.dump([a,b], open("trial.p", "wb"))

c,d = pickle.load(open("trial.p","rb"))

print(c,d) ## To verify

4

คุณสามารถใช้kleptoซึ่งจัดเตรียมแคชถาวรไปยังหน่วยความจำดิสก์หรือฐานข้อมูล

dude@hilbert>$ python
Python 2.7.6 (default, Nov 12 2013, 13:26:39) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from klepto.archives import file_archive
>>> db = file_archive('foo.txt')
>>> db['1'] = 1
>>> db['max'] = max
>>> squared = lambda x: x**2
>>> db['squared'] = squared
>>> def add(x,y):
...   return x+y
... 
>>> db['add'] = add
>>> class Foo(object):
...   y = 1
...   def bar(self, x):
...     return self.y + x
... 
>>> db['Foo'] = Foo
>>> f = Foo()
>>> db['f'] = f  
>>> db.dump()
>>> 

จากนั้นหลังจากล่ามเริ่มต้นใหม่ ...

dude@hilbert>$ python
Python 2.7.6 (default, Nov 12 2013, 13:26:39) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from klepto.archives import file_archive
>>> db = file_archive('foo.txt')
>>> db
file_archive('foo.txt', {}, cached=True)
>>> db.load()
>>> db
file_archive('foo.txt', {'1': 1, 'add': <function add at 0x10610a0c8>, 'f': <__main__.Foo object at 0x10510ced0>, 'max': <built-in function max>, 'Foo': <class '__main__.Foo'>, 'squared': <function <lambda> at 0x10610a1b8>}, cached=True)
>>> db['add'](2,3)
5
>>> db['squared'](3)
9
>>> db['f'].bar(4)
5
>>> 

รับรหัสที่นี่: https://github.com/uqfoundation


7
OP ไม่ขอบิวท์อิน
Mike McKerns

4

แนวทางต่อไปนี้ดูเหมือนง่ายและสามารถใช้ได้กับตัวแปรที่มีขนาดแตกต่างกัน:

import hickle as hkl
# write variables to filename [a,b,c can be of any size]
hkl.dump([a,b,c], filename)

# load variables from filename
a,b,c = hkl.load(filename)

hickleแพคเกจที่มีประสิทธิภาพมากขึ้น (ข้อผิดพลาดน้อย) และได้ง่าย pickle(รหัสน้อยกว่า)
user2340939
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.