shelve --- ماندگاری اشیاء در پایتون¶
کد منبع: Lib/shelve.py
یک «قفسه» (shelf) شیء پایا و دیکشنریمانند است. تفاوت آن با پایگاههای داده «dbm» در این است که مقادیر (نه کلیدها!) در یک قفسه میتوانند اساساً اشیاء پایتونی دلخواهی باشند — هر چیزی که ماژول pickle بتواند آن را مدیریت کند. این شامل بیشتر نمونههای کلاس، انواع داده بازگشتی و اشیایی میشود که حاوی تعداد زیادی زیرشیء مشترک هستند. کلیدها رشتههای معمولی هستند.
- shelve.open(filename, flag='c', protocol=None, writeback=False)¶
یک دیکشنری پایا را باز میکند. نام پرونده مشخصشده، نام پرونده پایه برای پایگاه دادهی زیربنایی است. بهعنوان اثر جانبی، ممکن است پسوندی به نام پرونده اضافه شود و بیش از یک پرونده ایجاد شود. بهطور پیشفرض، پرونده پایگاه دادهی زیربنایی برای خواندن و نوشتن باز میشود. پارامتر اختیاری flag همان تفسیر پارامتر flag در
dbm.open()را دارد.بهطور پیشفرض، پیکلهای ایجادشده با
pickle.DEFAULT_PROTOCOLبرای سریالسازی مقادیر استفاده میشوند. نسخهی پروتکل پیکل را میتوان با پارامتر protocol مشخص کرد.به دلیل معناشناسی پایتون، یک shelf نمیتواند بداند چه زمانی یک آیتم تغییرپذیر در دیکشنری پایا تغییر میکند. بهطور پیشفرض، اشیای تغییرکرده فقط زمانی نوشته میشوند که به shelf انتساب داده شوند (به مثال مراجعه کنید). اگر پارامتر اختیاری writeback روی
Trueتنظیم شود، همه آیتمهای دسترسییافته نیز در نهانگاه حافظه ذخیره میشوند و درsync()وclose()بازنویسی میشوند؛ این موضوع میتواند تغییر دادن آیتمهای تغییرپذیر در دیکشنری پایا را آسانتر کند، اما اگر به آیتمهای زیادی دسترسی پیدا شود، میتواند حجم بسیار زیادی از حافظه را برای نهانگاه مصرف کند و عملیات close را بسیار کند سازد، زیرا همه آیتمهای دسترسییافته بازنویسی میشوند (هیچ راهی برای تشخیص اینکه کدام آیتمهای دسترسییافته تغییرپذیرند، و نه اینکه کدامیک واقعاً تغییر کردهاند، وجود ندارد).تغییر یافته در نسخهی 3.10:
pickle.DEFAULT_PROTOCOLاکنون بهعنوان پروتکل پیشفرض pickle استفاده میشود.تغییر یافته در نسخهی 3.11: path-like object را برای نام پرونده میپذیرد.
توجه
به بسته شدن خودکار قفسه (shelf) اتکا نکنید؛ همیشه وقتی دیگر به آن نیاز ندارید،
close()را بهصراحت فراخوانی کنید، یا ازshelve.open()بهعنوان مدیر زمینه استفاده کنید:with shelve.open('spam') as db: db['eggs'] = 'eggs'
هشدار
از آنجا که ماژول shelve بر پایه pickle است، بارگذاری یک قفسه (shelf) از یک منبع غیرقابلاعتماد امن نیست. مانند pickle، بارگذاری یک قفسه (shelf) میتواند کد دلخواه را اجرا کند.
اشیای Shelf از بیشتر متدها و عملیاتهایی که دیکشنریها پشتیبانی میکنند، پشتیبانی میکنند (بهجز کپیسازی، سازندهها و عملگرهای | و |=). این کار گذار از اسکریپتهای مبتنی بر دیکشنری به اسکریپتهای نیازمند ذخیرهسازی پایا را آسان میکند.
از دو متد اضافی پشتیبانی میشود:
- Shelf.sync()¶
اگر قفسه (shelf) با writeback برابر با
Trueباز شده باشد، تمام ورودیهای نهانگاه را بازنویسی میکند. همچنین در صورت امکان، نهانگاه را خالی میکند و دیکشنری پایا روی دیسک را همگامسازی میکند. این متد بهطور خودکار هنگامی که قفسه (shelf) باclose()بسته میشود، فراخوانی میشود.
- Shelf.close()¶
همگامسازی و بستن شیء dict پایا. عملیات روی یک shelf بسته با
ValueErrorشکست خواهد خورد.
همچنین ملاحظه نمائید
دستور دیکشنری پایا با قالبهای ذخیرهسازی با پشتیبانی گسترده و دارای سرعت دیکشنریهای بومی.
محدودیتها¶
انتخاب بستهی پایگاه دادهای که استفاده خواهد شد (مانند
dbm.ndbmیاdbm.gnu) به این بستگی دارد که کدام رابط در دسترس باشد. بنابراین باز کردن پایگاه داده بهصورت مستقیم با استفاده ازdbmایمن نیست. پایگاه داده نیز (متأسفانه) در صورت استفاده ازdbmمشمول محدودیتهای آن است — این بدان معناست که بازنمایی pickleشده (pickled representation) از اشیاء ذخیرهشده در پایگاه داده باید نسبتاً کوچک باشد، و در موارد نادر ممکن است برخورد کلیدها باعث شود پایگاه داده از پذیرفتن بهروزرسانیها خودداری کند.ماژول
shelveاز دسترسی همزمان خواندن/نوشتن به اشیای ذخیرهشده در shelf پشتیبانی نمیکند. (چندین دسترسی خواندن همزمان بیخطر است.) هنگامی که برنامهای یک shelf را برای نوشتن باز نگه داشته است، هیچ برنامه دیگری نباید آن را برای خواندن یا نوشتن باز نگه دارد. میتوان از قفلگذاری پرونده در یونیکس برای حل این مسئله استفاده کرد، اما این رفتار در نسخههای مختلف یونیکس متفاوت است و به دانش دربارهی پیادهسازی پایگاه دادهی استفادهشده نیاز دارد.در macOS،
dbm.ndbmمیتواند هنگام بهروزرسانیها بدون هشدار پرونده پایگاه داده را خراب کند، که این میتواند هنگام تلاش برای خواندن از پایگاه داده باعث فروپاشیهای سخت شود.
- class shelve.Shelf(dict, protocol=None, writeback=False, keyencoding='utf-8')¶
زیرکلاسی از
collections.abc.MutableMappingکه مقادیر پیکلشده را در شیء dict ذخیره میکند.بهطور پیشفرض، از پیکلهای ایجادشده با
pickle.DEFAULT_PROTOCOLبرای سریالسازی مقادیر استفاده میشود. نسخهی پروتکل پیکل را میتوان با پارامتر protocol مشخص کرد. برای بحثی دربارهی پروتکلهای پیکل، مستنداتpickleرا ببینید.اگر پارامتر writeback برابر
Trueباشد، شیء نهانگاهی از تمام آیتمهای دسترسیشده را نگه میدارد و آنها را در زمان sync و close به دیکشنری بازمینویسد. این امر عملیات طبیعی روی آیتمهای تغییرپذیر را ممکن میسازد، اما میتواند حافظه بسیار بیشتری مصرف کند و باعث شود sync و close زمان زیادی طول بکشند.پارامتر keyencoding کدگذاریای است که برای کدگذاری کلیدها پیش از استفاده از آنها در دیکشنری زیرین به کار میرود.
یک شیء
Shelfهمچنین میتواند بهعنوان مدیر زمینه استفاده شود، که در این صورت با پایان یافتن بلوکwithبهطور خودکار بسته میشود.تغییر یافته در نسخهی 3.2: پارامتر keyencoding افزوده شد؛ پیشتر، کلیدها همیشه با UTF-8 کدگذاری میشدند.
تغییر یافته در نسخهی 3.4: پشتیبانی از مدیر زمینه افزوده شد.
تغییر یافته در نسخهی 3.10:
pickle.DEFAULT_PROTOCOLاکنون بهعنوان پروتکل پیشفرض pickle استفاده میشود.
- class shelve.BsdDbShelf(dict, protocol=None, writeback=False, keyencoding='utf-8')¶
یک زیرکلاس از
Shelfکه متدهایfirst()،next()،previous()،last()وset_location()را ارائه میدهد. این متدها در ماژول شخص ثالثbsddbاز pybsddb در دسترس هستند، اما در سایر ماژولهای پایگاه داده در دسترس نیستند. شیء dict که به سازنده ارسال میشود باید از آن متدها پشتیبانی کند. این کار معمولاً با فراخوانی یکی ازbsddb.hashopen()،bsddb.btopen()یاbsddb.rnopen()انجام میشود. پارامترهای اختیاری protocol، writeback و keyencoding همان تفسیری را دارند که برای کلاسShelfدارند.
- class shelve.DbfilenameShelf(filename, flag='c', protocol=None, writeback=False)¶
زیرکلاسی از
Shelfکه یک filename را بهجای یک شیء دیکشنریمانند میپذیرد. پرونده زیربنایی با استفاده ازdbm.open()باز خواهد شد. بهطور پیشفرض، پرونده ایجاد میشود و برای خواندن و نوشتن باز میشود. پارامتر اختیاری flag همان تفسیری را دارد که برای تابعopen()وجود دارد. پارامترهای اختیاری protocol و writeback همان تفسیری را دارند که برای کلاسShelfوجود دارد.
مثال¶
برای جمعبندی رابط (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