किसी ऑब्जेक्ट को सहेजना (डेटा दृढ़ता)


233

मैंने इस तरह एक वस्तु बनाई है:

company1.name = 'banana' 
company1.value = 40

मैं इस वस्तु को बचाना चाहूंगा। मैं उसे कैसे कर सकता हूँ?


1
उन लोगों के लिए उदाहरण देखें जो एक सरल उदाहरण के लिए यहां आते हैं कि अचार का उपयोग कैसे करें।
मार्टिन थोमा

@MartinThoma: आप (प्रतीत होता है) स्वीकार किए गए एक ( जुड़े प्रश्न का ) का उत्तर क्यों पसंद करते हैं ?
मार्टीन्यू

जिस समय मैं जुड़ा था, स्वीकृत जवाब नहीं था protocol=pickle.HIGHEST_PROTOCOL। मेरा जवाब अचार का विकल्प भी देता है।
मार्टिन थोमा

जवाबों:


449

आप 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) बनामpickle

यह लगभग हमेशा बेहतर होता है कि वास्तव में cPickleमॉड्यूल का उपयोग करें, बजाय इसके pickleकि पूर्व को C में लिखा गया है और बहुत तेज है। उनके बीच कुछ सूक्ष्म अंतर हैं, लेकिन ज्यादातर स्थितियों में वे समकक्ष हैं और सी संस्करण बहुत बेहतर प्रदर्शन प्रदान करेगा। इसे स्विच करना आसान नहीं हो सकता है, बस importस्टेटमेंट को इस में बदलें :

import cPickle as pickle

पायथन 3 में, cPickleका नाम बदल दिया गया था _pickle, लेकिन ऐसा करना अब आवश्यक नहीं है क्योंकि pickleमॉड्यूल अब स्वचालित रूप से करता है - देखें कि पायथन 3 में अचार और _pickle के बीच क्या अंतर है?

यह सुनिश्चित करने के लिए कि आप अपने कोड को हमेशा C संस्करण का उपयोग करेंगे जब यह पायथन 2 और 3 दोनों में उपलब्ध होगा:

try:
    import cPickle as pickle
except ModuleNotFoundError:
    import pickle

डेटा स्ट्रीम प्रारूप (प्रोटोकॉल)

pickleकई अलग-अलग, पायथन-विशिष्ट, स्वरूपों में फ़ाइलों को पढ़ और लिख सकते हैं, जिन्हें दस्तावेज में वर्णित प्रोटोकॉल कहा जाता है , "प्रोटोकॉल संस्करण 0" ASCII है और इसलिए "मानव-पठनीय" है। संस्करण> 0 द्विआधारी हैं और उपलब्ध सबसे अधिक यह निर्भर करता है कि पायथन के किस संस्करण का उपयोग किया जा रहा है। डिफ़ॉल्ट भी पायथन संस्करण पर निर्भर करता है। पायथन 2 में डिफ़ॉल्ट प्रोटोकॉल संस्करण था , लेकिन पायथन 3.8.1 में, यह प्रोटोकॉल संस्करण है । पायथन 3.x में मॉड्यूल को इसमें जोड़ा गया था, लेकिन यह पायथन 2 में मौजूद नहीं है।04pickle.DEFAULT_PROTOCOL

सौभाग्य से 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...

नोट : यदि आप पाइथन के विभिन्न संस्करणों को चलाने वाले वातावरण में हैं, तो आप शायद एक विशिष्ट प्रोटोकॉल संख्या का स्पष्ट रूप से उपयोग करना चाहते हैं (अर्थात हार्डकोड) जो कि सभी पढ़ सकते हैं (बाद के संस्करण आम तौर पर पहले वाले द्वारा उत्पादित फ़ाइलों को पढ़ सकते हैं) ।

कई वस्तुओं

एक अचार फ़ाइल जबकि कर सकते हैं जैसा कि ऊपर के नमूने में दिखाया गया है जब उनमें से एक अज्ञात नंबर है मसालेदार वस्तुओं के किसी भी संख्या, होते हैं, यह अक्सर उन सब को, variably आकार कंटेनर के कुछ प्रकार में स्टोर करने के लिए एक तरह आसान है 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))

1
यह मेरे लिए दुर्लभ है क्योंकि मैं कल्पना की एक वस्तु को बचाने के लिए एक आसान तरीका होगा ... की तरह 'saveobject कुछ (company1, c: \ mypythonobjects)
Peterstone

4
@ पेटरस्टोन: यदि आप केवल एक वस्तु को स्टोर करना चाहते हैं, तो आपको मेरे उदाहरण में केवल आधे से अधिक कोड की आवश्यकता होगी - मैंने उद्देश्यपूर्ण तरीके से इसे लिखा था कि मैंने यह दिखाया कि एक से अधिक वस्तु को कैसे बचाया जा सकता है (और बाद में वापस पढ़ें उसी फ़ाइल से)।
मार्टीन्यू

1
@Peterstone, जिम्मेदारियों के अलग होने का एक बहुत अच्छा कारण है। इस तरह से कोई सीमा नहीं है कि अचार प्रक्रिया के डेटा का उपयोग कैसे किया जा रहा है। आप इसे डिस्क पर स्टोर कर सकते हैं या आप इसे नेटवर्क कनेक्शन के साथ भी भेज सकते हैं।
हराल्ड स्किरीच

3
@martinaeau, यह डिस्क के लिए एक वस्तु को बचाने के लिए सिर्फ एक फ़ंक्शन होने के बारे में टिप्पणी के जवाब में था। अचार की जिम्मेदारी केवल एक वस्तु को डेटा में बदलना है जिसे एक ठग के रूप में संभाला जा सकता है। फाइल में चीजों को लिखना, फाइल ऑब्जेक्ट जिम्मेदारी है। चीजों को अलग रखकर उच्च पुन: उपयोग को सक्षम बनाता है जैसे कि किसी नेटवर्क कनेक्शन में पिक किए गए डेटा को भेजने या डेटाबेस में संग्रहीत करने में सक्षम होने के नाते, सभी जिम्मेदारियां वास्तविक डेटा से अलग होती हैं <-> वस्तु रूपांतरण
हेराल्ड स्चिरिच

1
आप हटाने company1और company2। आप भी क्यों नहीं हटाते हैं Companyऔर दिखाते हैं कि क्या होता है?
माइक मैकेर्नस

49

मुझे लगता है कि यह एक बहुत मजबूत धारणा है कि ऑब्जेक्ट एक है 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। हम 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 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कोई ऑडियो ऑब्जेक्ट शामिल होता है, तो मैं एक जटिल चीज़ के साथ उपयोग करने की कोशिश कर रहा होता हूं (जो आशाजनक लगता है)।
मिकीएलएल

1
@ मायिकएलएल: आपको एक TypeErrorऐसा मिल रहा है जब आप वास्तव में क्या करते हैं? यह आमतौर पर एक वर्ग उदाहरण का संकेत देते समय गलत संख्या में तर्क होने का संकेत है। यदि यह उपरोक्त प्रश्न के वर्कफ़्लो का हिस्सा नहीं है, तो क्या आप इसे एक अन्य प्रश्न के रूप में पोस्ट कर सकते हैं, इसे मुझे ईमेल पर सबमिट कर सकते हैं, या इसे dillजीथब पेज पर एक मुद्दे के रूप में जोड़ सकते हैं ?
माइक मैककेर्न

3
निम्नलिखित में से किसी के लिए, यहां संबंधित प्रश्न @MikeLL पोस्ट किया गया है - उत्तर से, यह स्पष्ट रूप से एक dillमुद्दा नहीं था ।
मार्टिन 12

dilएल MemoryErrorहालांकि मुझे देता है ! ऐसा करता है cPickle, pickleऔर hickle
फरिद अलीजानी

4

आप अपने लिए काम करने के लिए किसी भी प्रकार के कैश का उपयोग कर सकते हैं । यह सभी विवरणों पर विचार करता है:

  • यह बैकेंड के रूप में डिल का उपयोग करता है , जो 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)

एनाकाचे myfuncपहली बार कॉल cachedirकरता है और फ़ाइलनाम के रूप में एक अद्वितीय पहचानकर्ता (फ़ंक्शन के नाम और इसके तर्कों के आधार पर) का उपयोग करके एक फ़ाइल के परिणाम को अचार करता है। किसी भी लगातार चलने पर, पिक की गई वस्तु लोड हो जाती है। यदि cachedirअजगर रनों के बीच संरक्षित है, तो पिक्स्ड ऑब्जेक्ट को पिछले पायथन रन से लिया जाता है।

किसी भी अधिक जानकारी के लिए प्रलेखन देखें


एक anycacheसे अधिक उदाहरणों को सहेजने के लिए कोई कैसे उपयोग करेगा , classजैसे कि, या कंटेनर जैसे listकि (किसी फ़ंक्शन को कॉल करने का परिणाम नहीं था)?
मार्टिन

2

company1Python3 के साथ अपने प्रश्न का उपयोग करके त्वरित उदाहरण ।

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"))
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.