ฉันได้สร้างวัตถุแบบนี้:
company1.name = 'banana'
company1.value = 40
ฉันต้องการบันทึกวัตถุนี้ ฉันจะทำสิ่งนั้นได้อย่างไร
protocol=pickle.HIGHEST_PROTOCOL
ในขณะที่ผมเชื่อมโยงกับคำตอบที่ได้รับการยอมรับไม่ได้ คำตอบของฉันยังให้ทางเลือกในการดอง
ฉันได้สร้างวัตถุแบบนี้:
company1.name = 'banana'
company1.value = 40
ฉันต้องการบันทึกวัตถุนี้ ฉันจะทำสิ่งนั้นได้อย่างไร
protocol=pickle.HIGHEST_PROTOCOL
ในขณะที่ผมเชื่อมโยงกับคำตอบที่ได้รับการยอมรับไม่ได้ คำตอบของฉันยังให้ทางเลือกในการดอง
คำตอบ:
คุณสามารถใช้pickle
โมดูลในไลบรารีมาตรฐาน นี่คือแอปพลิเคชันระดับต้นสำหรับตัวอย่างของคุณ:
import pickle
class Company(object):
def __init__(self, name, value):
self.name = name
self.value = value
with open('company_data.pkl', 'wb') as output:
company1 = Company('banana', 40)
pickle.dump(company1, output, pickle.HIGHEST_PROTOCOL)
company2 = Company('spam', 42)
pickle.dump(company2, output, pickle.HIGHEST_PROTOCOL)
del company1
del company2
with open('company_data.pkl', 'rb') as input:
company1 = pickle.load(input)
print(company1.name) # -> banana
print(company1.value) # -> 40
company2 = pickle.load(input)
print(company2.name) # -> spam
print(company2.value) # -> 42
นอกจากนี้คุณยังสามารถกำหนดยูทิลิตี้ง่าย ๆ ของคุณเองดังต่อไปนี้ซึ่งเปิดไฟล์และเขียนวัตถุเดียวไปยังมัน:
def save_object(obj, filename):
with open(filename, 'wb') as output: # Overwrites any existing file.
pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL)
# sample usage
save_object(company1, 'company1.pkl')
เนื่องจากนี่เป็นคำตอบที่ได้รับความนิยมฉันจึงต้องการสัมผัสกับหัวข้อการใช้งานขั้นสูงเล็กน้อย
cPickle
(หรือ_pickle
) vspickle
มันเกือบจะดีกว่าเสมอที่จะใช้cPickle
โมดูลจริงมากกว่าpickle
เพราะเดิมเขียนใน C และเร็วกว่ามาก มีความแตกต่างเล็กน้อยระหว่างพวกเขา แต่ในสถานการณ์ส่วนใหญ่พวกเขาเท่ากันและรุ่น C จะให้ประสิทธิภาพที่เหนือกว่าอย่างมาก สลับไปมันไม่อาจจะง่ายเพียงแค่เปลี่ยนimport
คำสั่งนี้:
import cPickle as pickle
ใน Python 3 cPickle
ถูกเปลี่ยนชื่อ_pickle
แต่การทำเช่นนี้ไม่จำเป็นอีกต่อไปเนื่องจากpickle
โมดูลทำหน้าที่นี้โดยอัตโนมัติ - ดูความแตกต่างระหว่าง pickle และ _pickle ใน python 3 .
บทสรุปคือคุณสามารถใช้สิ่งต่อไปนี้เพื่อให้แน่ใจว่ารหัสของคุณจะใช้เวอร์ชัน C เสมอเมื่อมีให้ใช้งานทั้ง Python 2 และ 3:
try:
import cPickle as pickle
except ModuleNotFoundError:
import pickle
pickle
สามารถอ่านและเขียนไฟล์ในรูปแบบที่แตกต่างกันเฉพาะ Python ที่เรียกว่าโปรโตคอลตามที่อธิบายไว้ในเอกสารประกอบ "โปรโตคอลรุ่น 0" คือ ASCII ดังนั้น "มนุษย์อ่านได้" เวอร์ชั่น> 0 เป็นเลขฐานสองและจำนวนสูงสุดที่มีอยู่นั้นขึ้นอยู่กับเวอร์ชันของ Python ที่ใช้อยู่ ค่าเริ่มต้นยังขึ้นอยู่กับเวอร์ชันของ Python ในหลาม 2 เริ่มต้นเป็นรุ่นพิธีสาร0
แต่ใน Python 3.8.1 4
ก็โปรโตคอลรุ่น ใน Python 3.x โมดูลมีการpickle.DEFAULT_PROTOCOL
เพิ่มเข้ามา แต่ไม่มีอยู่ใน Python 2
โชคดีที่มีการจดชวเลขสำหรับการpickle.HIGHEST_PROTOCOL
โทรทุกครั้ง (สมมติว่าเป็นสิ่งที่คุณต้องการและคุณมักจะทำ) เพียงใช้หมายเลขตัวอักษร-1
- คล้ายกับการอ้างอิงองค์ประกอบสุดท้ายของลำดับผ่านดัชนีลบ ดังนั้นแทนที่จะเขียน:
pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL)
คุณสามารถเขียน:
pickle.dump(obj, output, -1)
ไม่ว่าจะด้วยวิธีใดคุณจะต้องระบุโปรโตคอลเพียงครั้งเดียวหากคุณสร้างPickler
วัตถุเพื่อใช้ในการดำเนินการดองหลายรายการ:
pickler = pickle.Pickler(output, -1)
pickler.dump(obj1)
pickler.dump(obj2)
etc...
หมายเหตุ : หากคุณอยู่ในสภาพแวดล้อมที่ใช้ Python เวอร์ชันต่าง ๆ คุณอาจต้องการใช้ (เช่น hardcode) หมายเลขโปรโตคอลเฉพาะที่ทุกคนสามารถอ่านได้ (รุ่นที่ใหม่กว่าสามารถอ่านไฟล์ที่ผลิตโดยรุ่นก่อนหน้าได้) .
ในขณะที่ไฟล์ดองสามารถมีหมายเลขใด ๆ ของวัตถุดองดังแสดงในตัวอย่างข้างต้นเมื่อมีหมายเลขที่ไม่รู้จักพวกเขาก็มักจะง่ายต่อการจัดเก็บพวกเขาทั้งหมดในการจัดเรียงของภาชนะที่แตกขนาดบางเหมือนlist
, tuple
หรือdict
และการเขียน พวกเขาทั้งหมดไปยังไฟล์ในการโทรเดียว:
tech_companies = [
Company('Apple', 114.18), Company('Google', 908.60), Company('Microsoft', 69.18)
]
save_object(tech_companies, 'tech_companies.pkl')
และกู้คืนรายการและทุกสิ่งในภายหลังด้วย:
with open('tech_companies.pkl', 'rb') as input:
tech_companies = pickle.load(input)
ได้เปรียบที่สำคัญคือคุณไม่จำเป็นต้องรู้วิธีหลายกรณีที่วัตถุถูกบันทึกไว้ในเพื่อที่จะโหลดพวกเขากลับมาในภายหลัง (แม้ว่าการทำเช่นนั้นโดยไม่มีข้อมูลว่าเป็นไปได้ที่จะต้องมีรหัสเฉพาะเล็กน้อยบางคน) ดูคำตอบของคำถามที่เกี่ยวข้องการบันทึกและการโหลดวัตถุหลาย ๆ อันในไฟล์ดอง? สำหรับรายละเอียดเกี่ยวกับวิธีการต่าง ๆ ในการทำเช่นนี้ โดยส่วนตัวผมชอบ @Lutz Prechelt ของคำตอบที่ดีที่สุด นี่มันปรับให้เข้ากับตัวอย่างที่นี่:
class Company:
def __init__(self, name, value):
self.name = name
self.value = value
def pickled_items(filename):
""" Unpickle a file of pickled data. """
with open(filename, "rb") as f:
while True:
try:
yield pickle.load(f)
except EOFError:
break
print('Companies in pickle file:')
for company in pickled_items('company_data.pkl'):
print(' name: {}, value: {}'.format(company.name, company.value))
company1
company2
ทำไมคุณไม่ลบCompany
และแสดงว่าเกิดอะไรขึ้น
ฉันคิดว่ามันเป็นข้อสันนิษฐานที่แข็งแกร่งพอclass
สมควรที่จะสมมติว่าวัตถุนั้นเป็น เกิดอะไรขึ้นถ้ามันไม่ได้เป็นclass
? นอกจากนี้ยังมีสมมติฐานว่าวัตถุไม่ได้ถูกกำหนดไว้ในล่าม เกิดอะไรขึ้นถ้ามันถูกกำหนดไว้ในล่าม? นอกจากนี้จะเกิดอะไรขึ้นถ้ามีการเพิ่มแอตทริบิวต์แบบไดนามิก เมื่อวัตถุหลามบางตัวมีคุณสมบัติที่เพิ่มเข้ามา__dict__
หลังจากการสร้างpickle
ไม่เคารพการเพิ่มคุณสมบัติเหล่านั้น (เช่นมัน 'ลืม' พวกมันถูกเพิ่มเข้ามา - เนื่องจากpickle
อนุกรมเป็นอนุกรมโดยอ้างอิงจากคำจำกัดความของวัตถุ)
ในทุกกรณีpickle
และcPickle
อาจทำให้คุณล้มเหลวอย่างน่ากลัว
หากคุณต้องการบันทึกobject
(สร้างโดยพลการ) ซึ่งคุณมีคุณสมบัติ (เพิ่มในนิยามของวัตถุหรือหลังจากนั้น) ... ทางออกที่ดีที่สุดของคุณคือการใช้dill
ซึ่งสามารถทำให้เป็นอนุกรมได้เกือบทุกอย่างในงูหลาม
เราเริ่มด้วยคลาส ...
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[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.
>>> import pickle
>>> class Company:
... pass
...
>>> company1 = Company()
>>> company1.name = 'banana'
>>> company1.value = 40
>>> with open('company.pkl', 'wb') as f:
... pickle.dump(company1, f, pickle.HIGHEST_PROTOCOL)
...
>>>
ตอนนี้ปิดตัวลงและเริ่มต้นใหม่ ...
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[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.
>>> import pickle
>>> with open('company.pkl', 'rb') as f:
... company1 = pickle.load(f)
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1378, in load
return Unpickler(file).load()
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 858, in load
dispatch[key](self)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1090, in load_global
klass = self.find_class(module, name)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1126, in find_class
klass = getattr(mod, name)
AttributeError: 'module' object has no attribute 'Company'
>>>
โอ๊ะโอ… pickle
จัดการไม่ได้ มาลองdill
กัน เราจะโยนวัตถุประเภทอื่น (a lambda
) สำหรับการวัดที่ดี
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[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.
>>> import dill
>>> class Company:
... pass
...
>>> company1 = Company()
>>> company1.name = 'banana'
>>> company1.value = 40
>>>
>>> company2 = lambda x:x
>>> company2.name = 'rhubarb'
>>> company2.value = 42
>>>
>>> with open('company_dill.pkl', 'wb') as f:
... dill.dump(company1, f)
... dill.dump(company2, f)
...
>>>
และตอนนี้อ่านไฟล์
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[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.
>>> import dill
>>> with open('company_dill.pkl', 'rb') as f:
... company1 = dill.load(f)
... company2 = dill.load(f)
...
>>> company1
<__main__.Company instance at 0x107909128>
>>> company1.name
'banana'
>>> company1.value
40
>>> company2.name
'rhubarb'
>>> company2.value
42
>>>
มันได้ผล. เหตุผลpickle
ล้มเหลวและdill
ไม่เป็นเช่นนั้นdill
ถือว่า__main__
เป็นโมดูล (ส่วนใหญ่) และยังสามารถกำหนดคำนิยามคลาสดองแทนการดองโดยอ้างอิง (เช่นpickle
ไม่) เหตุผลที่dill
สามารถดองได้lambda
ก็คือมันให้ชื่อ ... จากนั้นความมหัศจรรย์สามารถเกิดขึ้นได้
ที่จริงแล้วมีวิธีที่ง่ายกว่าในการบันทึกวัตถุเหล่านี้ทั้งหมดโดยเฉพาะถ้าคุณมีวัตถุจำนวนมากที่คุณสร้างขึ้น เพียงทิ้งเซสชัน python ทั้งหมดและกลับมาใช้ใหม่ในภายหลัง
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[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.
>>> import dill
>>> class Company:
... pass
...
>>> company1 = Company()
>>> company1.name = 'banana'
>>> company1.value = 40
>>>
>>> company2 = lambda x:x
>>> company2.name = 'rhubarb'
>>> company2.value = 42
>>>
>>> dill.dump_session('dill.pkl')
>>>
ตอนนี้ปิดเครื่องคอมพิวเตอร์ของคุณไปเพลิดเพลินกับเอสเพรสโซหรืออะไรและกลับมาในภายหลัง ...
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[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.
>>> import dill
>>> dill.load_session('dill.pkl')
>>> company1.name
'banana'
>>> company1.value
40
>>> company2.name
'rhubarb'
>>> company2.value
42
>>> company2
<function <lambda> at 0x1065f2938>
ข้อเสียเปรียบหลักอย่างเดียวdill
คือไม่ได้เป็นส่วนหนึ่งของไลบรารีมาตรฐานของไพ ธ อน ดังนั้นหากคุณไม่สามารถติดตั้งแพ็กเกจหลามบนเซิร์ฟเวอร์ของคุณได้คุณจะไม่สามารถใช้งานได้
แต่ถ้าคุณมีความสามารถในการติดตั้งแพคเกจหลามในระบบของคุณคุณจะได้รับล่าสุดกับdill
และคุณจะได้รับการปล่อยตัวออกมารุ่นล่าสุดgit+https://github.com/uqfoundation/dill.git@master#egg=dill
pip install dill
TypeError: __new__() takes at least 2 arguments (1 given)
เมื่อพยายามใช้dill
(ซึ่งดูมีแนวโน้ม) กับวัตถุที่ค่อนข้างซับซ้อนซึ่งรวมถึงไฟล์เสียง
TypeError
เมื่อคุณทำอะไรใช่มั้ย โดยปกติแล้วจะเป็นสัญญาณของการมีจำนวนอาร์กิวเมนต์ที่ไม่ถูกต้องเมื่อสร้างอินสแตนซ์ของคลาส หากนี่ไม่ใช่ส่วนหนึ่งของเวิร์กโฟลว์ของคำถามข้างต้นคุณสามารถโพสต์เป็นคำถามอื่นส่งมาให้ฉันทางอีเมลหรือเพิ่มเป็นปัญหาในdill
หน้า GitHub?
dill
ปัญหา
dil
l ให้ฉันMemoryError
สิ! เพื่อไม่cPickle
, และpickle
hickle
คุณสามารถใช้anycacheเพื่อทำงานให้คุณ มันจะพิจารณารายละเอียดทั้งหมด:
pickle
โมดูลหลามเพื่อจัดการlambda
และคุณสมบัติหลามที่ดีทั้งหมดสมมติว่าคุณมีฟังก์ชันmyfunc
ที่สร้างอินสแตนซ์:
from anycache import anycache
class Company(object):
def __init__(self, name, value):
self.name = name
self.value = value
@anycache(cachedir='/path/to/your/cache')
def myfunc(name, value)
return Company(name, value)
Anycache เรียกใช้myfunc
ในครั้งแรกและดองผลลัพธ์ลงในไฟล์cachedir
โดยใช้ตัวระบุที่ไม่ซ้ำกัน (ขึ้นอยู่กับชื่อฟังก์ชันและอาร์กิวเมนต์) เป็นชื่อไฟล์ ในการรันต่อเนื่องใด ๆ วัตถุที่ถูกดองจะถูกโหลด หากcachedir
ถูกเก็บรักษาไว้ระหว่างการทำงานของงูหลามวัตถุที่ถูกดองจะถูกนำมาจากการทำงานของหลามก่อนหน้า
สำหรับรายละเอียดเพิ่มเติมโปรดดูเอกสารประกอบ
anycache
เพื่อบันทึกมากกว่าหนึ่งอินสแตนซ์ของพูดclass
หรือคอนเทนเนอร์เช่น a list
(นั่นไม่ใช่ผลลัพธ์ของการเรียกฟังก์ชัน) ได้อย่างไร
ตัวอย่างด่วนที่ใช้company1
จากคำถามของคุณด้วย python3
import pickle
# Save the file
pickle.dump(company1, file = open("company1.pickle", "wb"))
# Reload the file
company1_reloaded = pickle.load(open("company1.pickle", "rb"))
อย่างไรก็ตามตามที่ระบุไว้คำตอบดองมักล้มเหลว dill
ดังนั้นคุณควรใช้
import dill
# Save the file
dill.dump(company1, file = open("company1.pickle", "wb"))
# Reload the file
company1_reloaded = dill.load(open("company1.pickle", "rb"))