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

همچنین ملاحظه نمائید

ماژول dbm

رابط عام برای پایگاه‌های داده به سبک dbm.

ماژول pickle

سریال‌سازی اشیاء که shelve از آن استفاده می‌کند.