একটি অবজেক্ট সংরক্ষণ করা (ডাটা অধ্যবসায়)


233

আমি এই জাতীয় একটি বিষয় তৈরি করেছি:

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

আমি এই বস্তুটি সংরক্ষণ করতে চাই আমি এটা কিভাবে করবো?


1
আচার ব্যবহারের উপায় সম্পর্কে সাধারণ উদাহরণের জন্য এখানে আসা লোকদের উদাহরণ দেখুন ।
মার্টিন থোমা

@ মার্টিন থোমা: কেন আপনি (আপাতদৃষ্টিতে) অনুমোদিত উত্তরটির ( সংযুক্ত প্রশ্নের উত্তর) উত্তরটি পছন্দ করেন ?
মার্টিনো

আমি সংযুক্ত হওয়ার সময়, গ্রহণযোগ্য উত্তরটি ছিল না 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। তাদের মধ্যে কিছু সূক্ষ্ম পার্থক্য রয়েছে, তবে বেশিরভাগ পরিস্থিতিতে এগুলি সমতুল্য এবং সি সংস্করণটি দুর্দান্ততর পারফরম্যান্স সরবরাহ করবে। এটিতে স্যুইচ করা সহজ হতে পারে না, কেবল importবিবৃতিটি এতে পরিবর্তন করুন :

import cPickle as pickle

পাইথন 3-এ, cPickleনাম পরিবর্তন করা হয়েছিল _pickle, তবে pickleমডিউলটি এখন স্বয়ংক্রিয়ভাবে এটি করার পরে এটি করা আর দরকার নেই — দেখুন পাইথন 3-তে আচার এবং লঙ্কুর মধ্যে পার্থক্য কী?

রুনডাউনটি হ'ল আপনি পাইথন 2 এবং 3 উভয় ক্ষেত্রেই কোডটি সর্বদা সি সংস্করণ ব্যবহার করবে তা নিশ্চিত করার জন্য আপনি নীচের মতো কিছু ব্যবহার করতে পারেন :

try:
    import cPickle as pickle
except ModuleNotFoundError:
    import pickle

ডেটা স্ট্রিম ফর্ম্যাটগুলি (প্রোটোকল)

pickleডকুমেন্টেশনে বর্ণিত প্রোটোকল নামে একাধিক পৃথক পাইথন-নির্দিষ্ট, ফর্ম্যাটগুলিতে ফাইলগুলি পড়তে বা লিখতে পারে , "প্রোটোকল সংস্করণ 0" ASCII এবং তাই "মানব-পঠনযোগ্য"। সংস্করণ> 0 বাইনারি এবং সর্বোচ্চ পাওয়া যায় পাইথনের কোন সংস্করণ ব্যবহৃত হচ্ছে তার উপর নির্ভর করে। ডিফল্টটি পাইথন সংস্করণেও নির্ভর করে। পাইথন 2 এ ডিফল্টটি ছিল প্রোটোকল সংস্করণ , তবে পাইথন ৩.৮.১ এ এটি প্রোটোকল সংস্করণ । পাইথন ৩.x এ মডিউলে এটি যুক্ত হয়েছিল তবে পাইথন ২ তে এটি বিদ্যমান নেই।04pickle.DEFAULT_PROTOCOL

ভাগ্যক্রমে pickle.HIGHEST_PROTOCOLপ্রতিটি কলটিতে লেখার জন্য সংক্ষিপ্তসার রয়েছে (ধরে নিলে আপনি যা চান তাই করেন এবং আপনি সাধারণত করেন), কেবল আক্ষরিক নম্বরটি ব্যবহার করুন -1- aণাত্মক সূচকের মাধ্যমে ক্রমের শেষ উপাদানটি উল্লেখ করার অনুরূপ। সুতরাং, লেখার পরিবর্তে:

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...

দ্রষ্টব্য : আপনি যদি পাইথনের বিভিন্ন সংস্করণ চলমান পরিবেশে থাকেন তবে আপনি সম্ভবত স্পষ্টভাবে একটি নির্দিষ্ট প্রোটোকল নম্বর ব্যবহার করতে চাইবেন যা তারা সকলেই পড়তে পারে (পরবর্তী সংস্করণগুলি সাধারণত পূর্ববর্তীগুলির দ্বারা নির্মিত ফাইলগুলি পড়তে পারে) ।

একাধিক অবজেক্ট

একটি জরান ফাইল যদিও পারেন যেমন, উপরের নমুনা দেখানো আছে যখন তাদের একটি অজানা নম্বর এর জরা বস্তু যে কোন সংখ্যার রয়েছে, এটা প্রায়ই তাদের সবাইকে, অসম আকারের ধারক কিছু বাছাই সংরক্ষণ করার জন্য একটি মত সহজ 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)

এর বড় সুবিধাটি হ'ল আপনার এগুলি পুনরায় লোড করার জন্য কতটি অবজেক্ট ইনস্ট্যানস সংরক্ষণ করা হয়েছে তা জানতে হবে না (যদিও তথ্যটি না দিয়ে এটি করা সম্ভব, এটি কিছুটা বিশেষায়িত কোডের প্রয়োজন)। সম্পর্কিত প্রশ্নের উত্তরগুলি দেখুন আচার ফাইলে একাধিক বস্তু সংরক্ষণ এবং লোড হচ্ছে? এটি করার বিভিন্ন উপায়ে বিশদের জন্য। ব্যক্তিগতভাবে আমি @ লুটজ প্রিচেল্টের উত্তরটি সবচেয়ে ভাল পছন্দ করি। এটি এখানে উদাহরণগুলির সাথে মানিয়ে নেওয়া হয়েছে:

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, গ: \ mypythonobjects)
Peterstone

4
@ পিটারস্টোন: আপনি যদি কেবল একটি বস্তু সঞ্চয় করতে চান তবে আমার উদাহরণ হিসাবে কেবলমাত্র প্রায় অর্ধেক কোডের প্রয়োজন হবে - আমি উদ্দেশ্যমূলকভাবে এটি লিখেছিলাম যেভাবে কীভাবে একাধিক বস্তুর মধ্যে সংরক্ষণ করা যায় (এবং পরে আবার পড়ুন) থেকে) একই ফাইল।
মার্টিনিউ

1
@ পিটারস্টোন, দায়িত্বগুলি পৃথক করার খুব ভাল কারণ রয়েছে। এইভাবে পিকিং প্রক্রিয়া থেকে ডেটা কীভাবে ব্যবহৃত হচ্ছে তার কোনও সীমাবদ্ধতা নেই। আপনি এটি ডিস্কে সঞ্চয় করতে পারেন বা আপনি এটি কোনও নেটওয়ার্ক সংযোগ জুড়ে পাঠাতে পারেন।
হ্যারাল্ড শাইরিখ

3
@ স্মার্টিনা, এটি ডিসটনে কোনও বস্তু সংরক্ষণ করার জন্য একটির একটি মাত্র ফাংশন থাকা উচিত বলে মন্তব্য করার প্রতিক্রিয়াতে ছিল। আচার দায়িত্ব শুধুমাত্র ডেটা একটি খণ্ড যেমন নাড়াচাড়া করতে পারেন মধ্যে একটি বস্তুর বিরত রাখতে। ফাইলগুলিতে জিনিসগুলি লেখাই ফাইলের বিষয়বস্তুর দায়িত্ব। বিষয়গুলিকে পৃথক করে রাখার ফলে উচ্চতর পুনঃব্যবহার সক্ষম হয় যেমন একটি নেটওয়ার্ক সংযোগ জুড়ে আচারযুক্ত ডেটা প্রেরণ করতে সক্ষম হওয়া বা এটি একটি ডাটাবেসে সংরক্ষণ করা, সমস্ত দায়িত্ব প্রকৃত ডেটা থেকে পৃথক <-> অবজেক্ট রূপান্তর
হ্যারাল্ড শাইরিখ

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এটি পরিচালনা করতে পারে না। চেষ্টা করা যাক dilllambdaভাল পরিমাপের জন্য আমরা অন্য একটি বস্তুর প্রকার (ক ) নিক্ষেপ করব ।

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__একটি মডিউল (অধিকাংশ অংশ জন্য) -এর মত, এবং এছাড়াও রেফারেন্স দ্বারা পরিবর্তে pickling বর্গ সংজ্ঞা জরান করতে পারেন (মত 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(যা আশাব্যঞ্জক বলে মনে হচ্ছে) getting
মাইকিএলএল

1
@ মাইকআইএল: আপনি TypeErrorযখন ঠিকঠাক করবেন তখন আপনি পাচ্ছেন ? এটি সাধারণত কোনও শ্রেণীর উদাহরণ ইনস্ট্যান্ট করার সময় ভুল সংখ্যক যুক্তিযুক্ত থাকার চিহ্ন। যদি এটি উপরের প্রশ্নের কর্মপ্রবাহের অংশ না হয়, আপনি কি এটি অন্য প্রশ্ন হিসাবে পোস্ট করতে পারেন, ইমেলের মাধ্যমে তা আমার কাছে জমা দিতে বা dillগিথুব পৃষ্ঠায় কোনও সমস্যা হিসাবে যুক্ত করতে পারেন ?
মাইক ম্যাকার্নস

3
যে কেউ অনুসরণ করে, এখানে মাইকেএলএল সম্পর্কিত প্রশ্নটি পোস্ট করা হয়েছে - উত্তর থেকে, সম্ভবত এটি কোনও dillসমস্যা ছিল না ।
মার্টিনিউ

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

company1পাইথন 3 সহ আপনার প্রশ্ন থেকে দ্রুত উদাহরণ ।

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"))
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.