การบันทึกและการโหลดวัตถุและการใช้ดอง


115

ฉันกำลังพยายามบันทึกและโหลดวัตถุโดยใช้pickleโมดูล
ก่อนอื่นฉันประกาศวัตถุของฉัน:

>>> class Fruits:pass
...
>>> banana = Fruits()

>>> banana.color = 'yellow'
>>> banana.value = 30

หลังจากนั้นฉันเปิดไฟล์ชื่อ 'Fruits.obj' (ก่อนหน้านี้ฉันสร้างไฟล์. txt ใหม่และฉันเปลี่ยนชื่อ 'Fruits.obj'):

>>> import pickle
>>> filehandler = open(b"Fruits.obj","wb")
>>> pickle.dump(banana,filehandler)

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

file = open("Fruits.obj",'r')
object_file = pickle.load(file)

แต่ฉันมีข้อความนี้:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python31\lib\pickle.py", line 1365, in load
encoding=encoding, errors=errors).load()
ValueError: read() from the underlying stream did notreturn bytes

ฉันไม่รู้ว่าต้องทำอย่างไรเพราะฉันไม่เข้าใจข้อความนี้ มีใครรู้บ้างว่าฉันจะโหลดวัตถุ 'กล้วย' ได้อย่างไร ขอบคุณ!

แก้ไข: ตามที่คุณบางคนแนะนำฉันใส่:

>>> import pickle
>>> file = open("Fruits.obj",'rb')

ไม่มีปัญหา แต่สิ่งต่อไปที่ฉันใส่คือ:

>>> object_file = pickle.load(file)

และฉันมีข้อผิดพลาด:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python31\lib\pickle.py", line 1365, in load
encoding=encoding, errors=errors).load()
EOFError


คำตอบ:


75

สำหรับปัญหาที่สองของคุณ:

 Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File "C:\Python31\lib\pickle.py", line
 1365, in load encoding=encoding,
 errors=errors).load() EOFError

หลังจากที่คุณอ่านเนื้อหาของไฟล์แล้วตัวชี้ไฟล์จะอยู่ท้ายไฟล์ - จะไม่มีข้อมูลให้อ่านเพิ่มเติม คุณต้องกรอกลับไฟล์เพื่อที่จะอ่านตั้งแต่ต้นอีกครั้ง:

file.seek(0)

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

ในที่สุด cPickle คือการนำโมดูลดองใน C ไปใช้งานได้เร็วขึ้นดังนั้น:

In [1]: import cPickle

In [2]: d = {"a": 1, "b": 2}

In [4]: with open(r"someobject.pickle", "wb") as output_file:
   ...:     cPickle.dump(d, output_file)
   ...:

# pickle_file will be closed at this point, preventing your from accessing it any further

In [5]: with open(r"someobject.pickle", "rb") as input_file:
   ...:     e = cPickle.load(input_file)
   ...:

In [7]: print e
------> print(e)
{'a': 1, 'b': 2}

"d = {" a ": 1," b ": 2}" โครงสร้างข้อมูลประเภทนี้เป็นแบบใด
Peterstone

1
@Peterstone: {"a": 1, "b": 2}สร้างพจนานุกรมด้วยคีย์"a"และ"b"อยู่ในนั้น สิ่งนี้เรียกว่านิพจน์การแสดงพจนานุกรมในเอกสารออนไลน์ เป็นเพียงวิธีหนึ่งในหลาย ๆ วิธีที่สามารถสร้างวัตถุประเภทdictซึ่งเป็นหนึ่งในประเภทข้อมูลในตัวมาตรฐานที่มีอยู่ใน Python ได้
martineau

2
เหตุใดตัวอักษร 'r' จึงใช้ชื่อไฟล์ ฉันไม่เห็นสิ่งนั้นในเอกสาร นอกจากนี้ยังทำให้ยากที่จะใช้ตัวแปรสำหรับชื่อไฟล์
SherylHohman

8
ดูคำตอบนี้ในวันนี้และสังเกตว่ามันใช้กับ Python 2.x เท่านั้น ใน Python 3.x ควรใช้โดยตรงpickleซึ่งจะนำเข้าcpickleโดยอัตโนมัติหากกระป๋อง docs.python.org/3.1/whatsnew/3.0.html#library-changes
Eskapp

41

สิ่งต่อไปนี้ใช้ได้กับฉัน:

class Fruits: pass

banana = Fruits()

banana.color = 'yellow'
banana.value = 30

import pickle

filehandler = open("Fruits.obj","wb")
pickle.dump(banana,filehandler)
filehandler.close()

file = open("Fruits.obj",'rb')
object_file = pickle.load(file)
file.close()

print(object_file.color, object_file.value, sep=', ')
# yellow, 30

สิ่งนี้ใช้ได้ผลกับฉัน แต่สิ่งที่ฉันแสวงหาคือปิดเซสชันเปิดใหม่และโหลดสิ่งที่ฉันบันทึกไว้ในเซสชันที่ผ่านมา ฉันปิดเซสชันหลังจากวางบรรทัด "filehandler.close ()" แล้วฉันก็เปิดอันใหม่และฉันใส่โค้ดที่เหลือของคุณจากนั้นใส่ "object_file = pickle.load (file)" ฉันได้รับข้อผิดพลาดนี้: Traceback ( โทรล่าสุดล่าสุด): ไฟล์ "<pyshell # 5>" บรรทัด 1 ใน <module> object_file = pickle.load (file) File "C: \ Python31 \ lib \ pickle.py" บรรทัด 1365 ในการเข้ารหัสโหลด = การเข้ารหัสข้อผิดพลาด = ข้อผิดพลาด) .load () AttributeError: วัตถุ 'module' ไม่มีแอตทริบิวต์ 'Fruits'
Peterstone

3
@Peterstone: ในเซสชันที่สองคุณจะต้องมีคำจำกัดความที่class Fruitsกำหนดไว้เพื่อให้pickle.load()สามารถสร้างวัตถุขึ้นใหม่จากข้อมูลที่บันทึกไว้ในไฟล์ไบนารี แนวทางปฏิบัติที่ดีที่สุดสำหรับประเภทนี้คือการใส่class Fruitsคำจำกัดความในไฟล์. py แยกต่างหาก (ทำให้เป็นโมดูลที่กำหนดเอง) จากนั้นimportโมดูลหรือรายการนั้นจากนั้นเมื่อใดก็ตามที่จำเป็น (เช่นทั้งสองเซสชัน) ตัวอย่างเช่นถ้าคุณใส่ไว้ในไฟล์ชื่อMyDataDefs.pyคุณก็สามารถเขียนfrom MyDataDefs import Fruitsได้ โปรดแจ้งให้เราทราบหากสิ่งนี้ไม่ชัดเจนเราจะอัปเดตคำตอบตามนั้น
martineau

ที่จริง PEP 8 แนะนำให้ใช้ตัวอักษรพิมพ์เล็กทั้งหมดสำหรับชื่อโมดูลดังนั้นตัวอย่างเช่นในตอนท้ายของความคิดเห็นล่าสุดของฉันควรจะได้รับในไฟล์ชื่อโดยใช้my_data_defs.py from my_data_defs import Fruits
martineau

24

คุณลืมอ่านเป็นไบนารีด้วย

ในส่วนการเขียนของคุณคุณมี:

open(b"Fruits.obj","wb") # Note the wb part (Write Binary)

ในส่วนการอ่านคุณมี:

file = open("Fruits.obj",'r') # Note the r part, there should be a b too

ดังนั้นแทนที่ด้วย:

file = open("Fruits.obj",'rb')

และมันจะทำงาน :)


สำหรับข้อผิดพลาดที่สองของคุณมักเกิดจากการไม่ปิด / ซิงค์ไฟล์อย่างถูกต้อง

ลองเขียนโค้ดนี้:

>>> import pickle
>>> filehandler = open(b"Fruits.obj","wb")
>>> pickle.dump(banana,filehandler)
>>> filehandler.close()

และสิ่งนี้ (ไม่เปลี่ยนแปลง) ให้อ่าน:

>>> import pickle
>>> file = open("Fruits.obj",'rb')
>>> object_file = pickle.load(file)

รุ่นใหม่กว่าจะใช้withคำสั่ง

สำหรับการเขียน:

>>> import pickle
>>> with open('Fruits.obj', 'wb') as fp:
>>>     pickle.dump(banana, fp)

สำหรับการอ่าน:

>>> import pickle
>>> with open('Fruits.obj', 'rb') as fp:
>>>     banana = pickle.load(fp)

1
ฉันใช้เวอร์ชันของคุณที่ใช้คำสั่ง with และฉันได้รับข้อความนี้: Traceback (โทรล่าสุดล่าสุด): ไฟล์ "<pyshell # 20>" บรรทัด 1 ใน <module> print (banana.color) AttributeError: 'Fruits' วัตถุไม่มีแอตทริบิวต์ "สี"
Peterstone


6

คุณไม่ได้เปิดไฟล์ในโหมดไบนารี

open("Fruits.obj",'rb')

ควรทำงาน.

สำหรับข้อผิดพลาดที่สองของคุณไฟล์มักจะว่างเปล่าซึ่งหมายความว่าคุณล้างข้อมูลโดยไม่ได้ตั้งใจหรือใช้ชื่อไฟล์ผิดหรืออะไรบางอย่าง

(นี่คือสมมติว่าคุณปิดเซสชันของคุณแล้วจริงๆถ้าไม่เป็นเช่นนั้นเป็นเพราะคุณไม่ได้ปิดไฟล์ระหว่างการเขียนและการอ่าน)

ฉันทดสอบรหัสของคุณแล้วและใช้งานได้


3

ดูเหมือนว่าคุณต้องการบันทึกอินสแตนซ์ของชั้นเรียนในแต่ละเซสชันและการใช้pickleเป็นวิธีที่ดีในการทำเช่นนี้ อย่างไรก็ตามมีแพ็คเกจที่เรียกkleptoว่าการบันทึกวัตถุลงในอินเทอร์เฟซพจนานุกรมดังนั้นคุณสามารถเลือกที่จะดองวัตถุและบันทึกลงในไฟล์ (ตามที่แสดงด้านล่าง) หรือดองวัตถุและบันทึกลงในฐานข้อมูลหรือแทนที่จะเป็น ใช้ผักดองใช้ json หรือตัวเลือกอื่น ๆ สิ่งที่ดีเกี่ยวกับ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('fruits.txt')
>>> class Fruits: pass
... 
>>> banana = Fruits()
>>> banana.color = 'yellow'
>>> banana.value = 30
>>> 
>>> db['banana'] = banana 
>>> 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('fruits.txt')
>>> db.load()
>>> 
>>> db['banana'].color
'yellow'
>>> 

Klepto ทำงานบน python2 และ python3

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


1

คุณสามารถใช้anycacheเพื่อทำงานให้คุณได้ สมมติว่าคุณมีฟังก์ชันmyfuncที่สร้างอินสแตนซ์:

from anycache import anycache

class Fruits:pass

@anycache(cachedir='/path/to/your/cache')    
def myfunc()
    banana = Fruits()
    banana.color = 'yellow'
    banana.value = 30
return banana

Anycache เรียกmyfuncในครั้งแรกและเก็บผลลัพธ์ไปยังไฟล์cachedirโดยใช้ตัวระบุเฉพาะ (ขึ้นอยู่กับชื่อฟังก์ชันและอาร์กิวเมนต์) เป็นชื่อไฟล์ ในการวิ่งติดต่อกันวัตถุดองจะถูกโหลด

หากcachedirถูกเก็บรักษาไว้ระหว่างการรัน python วัตถุดองจะถูกนำมาจากการรัน python ก่อนหน้านี้

อาร์กิวเมนต์ของฟังก์ชันจะถูกนำมาพิจารณาด้วย การใช้งาน refactored ทำงานในทำนองเดียวกัน:

from anycache import anycache

class Fruits:pass

@anycache(cachedir='/path/to/your/cache')    
def myfunc(color, value)
    fruit = Fruits()
    fruit.color = color
    fruit.value = value
return fruit
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.