shelve --- ماندگاری اشیاء در پایتون¶
کد منبع: Lib/shelve.py
یک «قفسه» (shelf) شیء پایا و دیکشنریمانند است. تفاوت آن با پایگاههای داده «dbm» در این است که مقادیر (نه کلیدها!) در یک قفسه میتوانند اساساً اشیاء پایتونی دلخواهی باشند — هر چیزی که ماژول pickle بتواند آن را مدیریت کند. این شامل بیشتر نمونههای کلاس، انواع داده بازگشتی و اشیایی میشود که حاوی تعداد زیادی زیرشیء مشترک هستند. کلیدها رشتههای معمولی هستند.
- shelve.open(filename, flag='c', protocol=None, writeback=False, *, serializer=None, deserializer=None)¶
یک دیکشنری پایا را باز میکند. نام پرونده مشخصشده، نام پرونده پایه برای پایگاه دادهی زیربنایی است. بهعنوان اثر جانبی، ممکن است پسوندی به نام پرونده اضافه شود و بیش از یک پرونده ایجاد شود. بهطور پیشفرض، پرونده پایگاه دادهی زیربنایی برای خواندن و نوشتن باز میشود. پارامتر اختیاری flag همان تفسیر پارامتر flag در
dbm.open()را دارد.بهطور پیشفرض، پیکلهای ایجادشده با
pickle.DEFAULT_PROTOCOLبرای سریالسازی مقادیر استفاده میشوند. نسخهی پروتکل پیکل را میتوان با پارامتر protocol مشخص کرد.به دلیل معناشناسی پایتون، یک shelf نمیتواند بداند چه زمانی یک آیتم تغییرپذیر در دیکشنری پایا تغییر میکند. بهطور پیشفرض، اشیای تغییرکرده فقط زمانی نوشته میشوند که به shelf انتساب داده شوند (به مثال مراجعه کنید). اگر پارامتر اختیاری writeback روی
Trueتنظیم شود، همه آیتمهای دسترسییافته نیز در نهانگاه حافظه ذخیره میشوند و درsync()وclose()بازنویسی میشوند؛ این موضوع میتواند تغییر دادن آیتمهای تغییرپذیر در دیکشنری پایا را آسانتر کند، اما اگر به آیتمهای زیادی دسترسی پیدا شود، میتواند حجم بسیار زیادی از حافظه را برای نهانگاه مصرف کند و عملیات close را بسیار کند سازد، زیرا همه آیتمهای دسترسییافته بازنویسی میشوند (هیچ راهی برای تشخیص اینکه کدام آیتمهای دسترسییافته تغییرپذیرند، و نه اینکه کدامیک واقعاً تغییر کردهاند، وجود ندارد).به طور پیشفرض،
shelveازpickle.dumps()وpickle.loads()برای سریالسازی و سریالزدایی استفاده میکند. این کار را میتوان با ارائهی serializer و deserializer به ترتیب تغییر داد.آرگومان serializer باید یک شیء فراخوانیپذیر باشد که یک شیء
objو protocol را به عنوان ورودی دریافت کند و بازنماییobjرا به عنوان یک شیء شبهبایت برگرداند؛ ممکن است مقدار protocol توسط سریالساز نادیده گرفته شود.آرگومان deserializer باید یک شیء فراخوانیپذیر باشد که یک شیء سریالشده را که به عنوان یک شیء
bytesداده شده است دریافت کند و شیء متناظر را برگرداند.اگر serializer داده شود اما deserializer داده نشود یا برعکس، یک
ShelveErrorبالا آورده میشود.تغییر یافته در نسخهی 3.10:
pickle.DEFAULT_PROTOCOLاکنون بهعنوان پروتکل پیشفرض pickle استفاده میشود.تغییر یافته در نسخهی 3.11: path-like object را برای نام پرونده میپذیرد.
تغییر یافته در نسخهی 3.15: توابع serializer و deserializer سفارشی را به جای
pickle.dumps()وpickle.loads()میپذیرد.نکته
به بسته شدن خودکار قفسه (shelf) اتکا نکنید؛ همیشه وقتی دیگر به آن نیاز ندارید،
close()را بهصراحت فراخوانی کنید، یا ازshelve.open()بهعنوان مدیر زمینه استفاده کنید:with shelve.open('spam') as db: db['eggs'] = 'eggs'
هشدار
از آنجا که ماژول shelve بر پایه pickle است، بارگذاری یک قفسه (shelf) از یک منبع غیرقابلاعتماد امن نیست. مانند pickle، بارگذاری یک قفسه (shelf) میتواند کد دلخواه را اجرا کند.
اشیای Shelf از بیشتر متدها و عملیاتهایی که دیکشنریها پشتیبانی میکنند، پشتیبانی میکنند (بهجز کپیسازی، سازندهها و عملگرهای | و |=). این کار گذار از اسکریپتهای مبتنی بر دیکشنری به اسکریپتهای نیازمند ذخیرهسازی پایا را آسان میکند.
از دو متد اضافی پشتیبانی میشود:
- Shelf.sync()¶
اگر قفسه با مقدار writeback تنظیمشده روی
Trueباز شده باشد، تمام درایوهای موجود در نهانگاه را به عقب بازنویسی کنید. همچنین در صورت امکان، نهانگاه را خالی کرده و دیکشنری پایا را روی دیسک همگامسازی کنید. این کار به صورت خودکار هنگام فراخوانیreorganize()یا بسته شدن قفسه باclose()انجام میشود.
- Shelf.reorganize()¶
متد
sync()را فراخوانی میکند و تلاش میکند با حذف فضای خالی ناشی از حذفها، فضای استفادهشده روی دیسک را کاهش دهد.اضافه شده در نسخهی 3.15.
- Shelf.close()¶
همگامسازی و بستن شیء dict پایا. عملیات روی یک shelf بسته با
ValueErrorشکست خواهد خورد.
همچنین ببینید
دستور دیکشنری پایا با قالبهای ذخیرهسازی با پشتیبانی گسترده و دارای سرعت دیکشنریهای بومی.
محدودیتها¶
انتخاب بستهی پایگاه دادهای که استفاده خواهد شد (مانند
dbm.ndbmیاdbm.gnu) به این بستگی دارد که کدام رابط در دسترس باشد. بنابراین باز کردن پایگاه داده بهصورت مستقیم با استفاده ازdbmایمن نیست. پایگاه داده نیز (متأسفانه) در صورت استفاده ازdbmمشمول محدودیتهای آن است — این بدان معناست که بازنمایی pickleشده (pickled representation) از اشیاء ذخیرهشده در پایگاه داده باید نسبتاً کوچک باشد، و در موارد نادر ممکن است برخورد کلیدها باعث شود پایگاه داده از پذیرفتن بهروزرسانیها خودداری کند.ماژول
shelveاز دسترسی همزمان خواندن/نوشتن به اشیای ذخیرهشده در shelf پشتیبانی نمیکند. (چندین دسترسی خواندن همزمان بیخطر است.) هنگامی که برنامهای یک shelf را برای نوشتن باز نگه داشته است، هیچ برنامه دیگری نباید آن را برای خواندن یا نوشتن باز نگه دارد. میتوان از قفلگذاری پرونده در یونیکس برای حل این مسئله استفاده کرد، اما این رفتار در نسخههای مختلف یونیکس متفاوت است و به دانش دربارهی پیادهسازی پایگاه دادهی استفادهشده نیاز دارد.در macOS،
dbm.ndbmمیتواند هنگام بهروزرسانیها بدون هشدار پرونده پایگاه داده را خراب کند، که این میتواند هنگام تلاش برای خواندن از پایگاه داده باعث فروپاشیهای سخت شود.ممکن است
Shelf.reorganize()برای همهی بستههای پایگاه داده در دسترس نباشد و هنگام فراخوانی ممکن است به طور موقت استفاده از منابع (به ویژه فضای دیسک) را افزایش دهد. علاوه بر این، هرگز به طور خودکار اجرا نمیشود و در عوض باید به طور صریح فراخوانی شود.
- class shelve.Shelf(dict, protocol=None, writeback=False, keyencoding='utf-8', *, serializer=None, deserializer=None)¶
زیرکلاسی از
collections.abc.MutableMappingکه مقادیر پیکلشده را در شیء dict ذخیره میکند.بهطور پیشفرض، از پیکلهای ایجادشده با
pickle.DEFAULT_PROTOCOLبرای سریالسازی مقادیر استفاده میشود. نسخهی پروتکل پیکل را میتوان با پارامتر protocol مشخص کرد. برای بحثی دربارهی پروتکلهای پیکل، مستنداتpickleرا ببینید.اگر پارامتر writeback برابر
Trueباشد، شیء نهانگاهی از تمام آیتمهای دسترسیشده را نگه میدارد و آنها را در زمان sync و close به دیکشنری بازمینویسد. این امر عملیات طبیعی روی آیتمهای تغییرپذیر را ممکن میسازد، اما میتواند حافظه بسیار بیشتری مصرف کند و باعث شود sync و close زمان زیادی طول بکشند.پارامتر keyencoding کدگذاریای است که برای کدگذاری کلیدها پیش از استفاده از آنها در دیکشنری زیرین به کار میرود.
پارامترهای serializer و deserializer همان تفسیری را دارند که در
open()وجود دارد.یک شیء
Shelfهمچنین میتواند بهعنوان مدیر زمینه استفاده شود، که در این صورت با پایان یافتن بلوکwithبهطور خودکار بسته میشود.تغییر یافته در نسخهی 3.2: پارامتر keyencoding افزوده شد؛ پیشتر، کلیدها همیشه با UTF-8 کدگذاری میشدند.
تغییر یافته در نسخهی 3.4: پشتیبانی از مدیر زمینه افزوده شد.
تغییر یافته در نسخهی 3.10:
pickle.DEFAULT_PROTOCOLاکنون بهعنوان پروتکل پیشفرض pickle استفاده میشود.تغییر یافته در نسخهی 3.15: پارامترهای serializer و deserializer اضافه شدند.
- class shelve.BsdDbShelf(dict, protocol=None, writeback=False, keyencoding='utf-8', *, serializer=None, deserializer=None)¶
زیرکلاسی از
Shelfکه متدهایfirst()،next()،previous()،last()وset_location()را ارائه میدهد. این موارد در ماژول شخص ثالثbsddbاز pybsddb موجود هستند اما در سایر ماژولهای پایگاه داده حضور ندارند. شیء dict ارسالشده به سازنده باید از این متدها پشتیبانی کند. این کار معمولاً با فراخوانی یکی از توابعbsddb.hashopen()،bsddb.btopen()یاbsddb.rnopen()انجام میشود. پارامترهای اختیاری protocol، writeback، keyencoding، serializer و deserializer همان تفسیری را دارند که درopen()دیده میشود.تغییر یافته در نسخهی 3.15: پارامترهای serializer و deserializer اضافه شدند.
- class shelve.DbfilenameShelf(filename, flag='c', protocol=None, writeback=False, *, serializer=None, deserializer=None)¶
زیرکلاسی از
Shelfکه به جای یک شیء دیکشنریمانند، یک filename را میپذیرد. پروندهی زیربنایی با استفاده ازdbm.open()باز خواهد شد. به طور پیشفرض، پرونده برای خواندن و نوشتن ایجاد و باز میشود. پارامتر اختیاری flag همان تفسیری را دارد که برای تابعopen()در نظر گرفته شده است. پارامترهای اختیاری protocol، writeback، serializer و deserializer همان تفسیری را دارند که درopen()وجود دارد.تغییر یافته در نسخهی 3.15: پارامترهای serializer و deserializer اضافه شدند.
مثال¶
برای جمعبندی رابط (key یک رشته است، data یک شیء دلخواه است):
import shelve
d = shelve.open(filename) # open -- file may get suffix added by low-level
# library
d[key] = data # store data at key (overwrites old data if
# using an existing key)
data = d[key] # retrieve a COPY of data at key (raise KeyError
# if no such key)
del d[key] # delete data stored at key (raises KeyError
# if no such key)
flag = key in d # true if the key exists
klist = list(d.keys()) # a list of all existing keys (slow!)
# as d was opened WITHOUT writeback=True, beware:
d['xx'] = [0, 1, 2] # this works as expected, but...
d['xx'].append(3) # *this doesn't!* -- d['xx'] is STILL [0, 1, 2]!
# having opened d without writeback=True, you need to code carefully:
temp = d['xx'] # extracts the copy
temp.append(5) # mutates the copy
d['xx'] = temp # stores the copy right back, to persist it
# or, d=shelve.open(filename,writeback=True) would let you just code
# d['xx'].append(5) and have it work as expected, BUT it would also
# consume more memory and make the d.close() operation slower.
d.close() # close it
استثناها¶
- exception shelve.ShelveError¶
استثنایی که وقتی یکی از آرگومانهای deserializer و serializer در
open()،Shelf،BsdDbShelfوDbfilenameShelfوجود نداشته باشد، بالا آورده میشود.آرگومانهای deserializer و serializer باید با هم داده شوند.
اضافه شده در نسخهی 3.15.