GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||
GeezerVison is showing python.github.io — collections --- انواع دادهی ظرف
|
تابع کارخانهای (factory function) برای ایجاد زیرکلاسهای تاپل با فیلدهای نامدار |
|
ظرفی فهرستمانند با امکان افزودن و برداشتن سریع در هر دو انتها |
|
کلاس دیکشنریمانند برای ایجاد یک نمای واحد از چندین نگاشت |
|
زیرکلاس دیکشنری برای شمارش اشیاء hashable |
|
زیرکلاسی از dict که ترتیب افزوده شدن آیتمها را به خاطر میسپارد |
|
زیرکلاس dict که برای تأمین مقادیر گمشده، یک تابع کارخانه را فراخوانی میکند |
|
پوششی دور اشیای دیکشنری برای زیرکلاسسازی آسانتر از dict |
|
پوششی بر روی اشیای فهرست برای زیرکلاسسازی آسانتر فهرست |
|
پوششی بر روی اشیاء رشتهای برای زیرکلاسسازی آسانتر از رشته |
ChainMap¶اضافه شده در نسخهی 3.3.
کلاس ChainMap برای پیوند سریع تعدادی نگاشت فراهم شده است تا بتوان با آنها بهعنوان یک واحد رفتار کرد. این کار اغلب بسیار سریعتر از ایجاد یک دیکشنری جدید و اجرای چندین فراخوانی update() است.
این کلاس میتواند برای شبیهسازی محدودههای تودرتو استفاده شود و در قالببندی مفید است.
یک ChainMap چندین دیکشنری یا نگاشتهای دیگر را در کنار هم قرار میدهد تا یک نمای واحد و بهروزرسانیپذیر ایجاد کند. اگر هیچ maps مشخص نشده باشد، یک دیکشنری خالی ارائه میشود تا یک زنجیره جدید همیشه حداقل یک نگاشت داشته باشد.
نگاشتهای زیربنایی در یک فهرست ذخیره میشوند. آن فهرست عمومی است و میتوان با استفاده از ویژگی maps به آن دسترسی پیدا کرد یا آن را بهروزرسانی کرد. هیچ وضعیت دیگری وجود ندارد.
جستوجوها نگاشتهای زیرین را بهترتیب جستوجو میکنند تا کلیدی پیدا شود. در مقابل، نوشتنها، بهروزرسانیها و حذفها تنها روی اولین نگاشت عمل میکنند.
یک ChainMap نگاشتهای زیربنایی را بهصورت ارجاعی در بر میگیرد. بنابراین، اگر یکی از نگاشتهای زیربنایی بهروزرسانی شود، آن تغییرات در ChainMap منعکس خواهند شد.
تمام متدهای معمول دیکشنری پشتیبانی میشوند. علاوه بر این، یک ویژگی maps، یک متد برای ایجاد زیرزمینههای جدید، و یک پراپرتی برای دسترسی به همه نگاشتها بهجز اولین نگاشت وجود دارد:
فهرستی از نگاشتها که کاربر میتواند آن را بهروزرسانی کند. این فهرست به ترتیب از نخستین مورد جستجوشده تا آخرین مورد جستجوشده مرتب شده است. این تنها وضعیت ذخیرهشده است و میتوان آن را برای تغییر نگاشتهایی که جستجو میشوند، تغییر داد. این فهرست باید همواره شامل دستکم یک نگاشت باشد.
یک ChainMap جدید برمیگرداند که شامل یک نگاشت جدید و به دنبال آن همهی نگاشتهای موجود در نمونه فعلی است. اگر m مشخص شده باشد، نگاشت جدید در ابتدای فهرست نگاشتها قرار میگیرد؛ اگر مشخص نشده باشد، از یک دیکشنری خالی استفاده میشود، بهطوری که فراخوانی d.new_child() معادل ChainMap({}, *d.maps) است. اگر آرگومانهای کلیدواژهای مشخص شده باشند، آنها نگاشت دادهشده یا دیکشنری خالی جدید را بهروزرسانی میکنند. این متد برای ایجاد زیرزمینههایی استفاده میشود که میتوانند بدون تغییر مقادیر هیچیک از نگاشتهای والد بهروزرسانی شوند.
تغییر یافته در نسخهی 3.4: پارامتر اختیاری m اضافه شد.
تغییر یافته در نسخهی 3.10: پشتیبانی از آرگومانهای کلیدواژهای افزوده شد.
ویژگیای که یک ChainMap جدید حاوی همهی نگاشتهای موجود در نمونهی جاری، بهجز اولین آنها را برمیگرداند. این ویژگی برای پرش از اولین نگاشت در جستجو مفید است. موارد استفاده مشابه موارد استفادهی کلیدواژهی nonlocal است که در محدودههای تودرتو استفاده میشود. این موارد استفاده همچنین مشابه موارد استفادهی تابع توکار super() است. ارجاع به d.parents معادل است با: ChainMap(*d.maps[1:]).
توجه داشته باشید که ترتیب تکرار یک ChainMap با پیمایش نگاشتها از آخر به اول تعیین میشود:
>>> baseline = {'music': 'bach', 'art': 'rembrandt'} >>> adjustments = {'art': 'van gogh', 'opera': 'carmen'} >>> list(ChainMap(adjustments, baseline)) ['music', 'art', 'opera']
این همان ترتیبی را میدهد که یک دنباله از فراخوانیهای dict.update() با شروع از آخرین نگاشت دارد:
>>> combined = baseline.copy() >>> combined.update(adjustments) >>> list(combined) ['music', 'art', 'opera']
تغییر یافته در نسخهی 3.9: پشتیبانی از عملگرهای | و |= که در PEP 584 مشخص شدهاند، افزوده شد.
همچنین ببینید
کلاس MultiContext در بسته CodeTools از Enthought، گزینههایی برای پشتیبانی از نوشتن در هر نگاشتی در زنجیره دارد.
کلاس Context جنگو برای قالببندی، زنجیرهای فقطخواندنی از نگاشتها است. این کلاس همچنین امکان افزودن و برداشتن زمینهها را، مشابه متد new_child() و ویژگی parents، فراهم میکند.
Nested Contexts recipe گزینههایی برای کنترل اینکه نوشتها و سایر تغییرات فقط بر اولین نگاشت اعمال شوند یا بر هر نگاشتی در زنجیره دارد.
ChainMap¶این بخش روشهای مختلفی را برای کار با نگاشتهای زنجیرهای نشان میدهد.
مثالی از شبیهسازی زنجیرهی جستوجوی داخلی پایتون:
import builtins pylookup = ChainMap(locals(), globals(), vars(builtins))
مثالی از اینکه آرگومانهای خط فرمان تعیینشده توسط کاربر بر متغیرهای محیطی اولویت داشته باشند و این متغیرها نیز بر مقادیر پیشفرض اولویت داشته باشند:
import os, argparse defaults = {'color': 'red', 'user': 'guest'} parser = argparse.ArgumentParser() parser.add_argument('-u', '--user') parser.add_argument('-c', '--color') namespace = parser.parse_args() command_line_args = {k: v for k, v in vars(namespace).items() if v is not None} combined = ChainMap(command_line_args, os.environ, defaults) print(combined['color']) print(combined['user'])
الگوهای نمونه برای استفاده از کلاس ChainMap جهت شبیهسازی زمینههای تودرتو:
c = ChainMap() # Create root context d = c.new_child() # Create nested child context e = c.new_child() # Child of c, independent from d e.maps[0] # Current context dictionary -- like Python's locals() e.maps[-1] # Root context -- like Python's globals() e.parents # Enclosing context chain -- like Python's nonlocals d['x'] = 1 # Set value in current context d['x'] # Get first key in the chain of contexts del d['x'] # Delete from current context list(d) # All nested values k in d # Check all nested values len(d) # Number of nested values d.items() # All nested items dict(d) # Flatten into a regular dictionary
کلاس ChainMap فقط بهروزرسانیها (نوشتنها و حذفها) را روی اولین نگاشت در زنجیره اعمال میکند، در حالی که جستوجوها کل زنجیره را جستجو میکنند. با این حال، اگر نوشتنها و حذفها در عمق بیشتری از زنجیره مورد نظر باشند، ساخت زیرکلاسی که کلیدهای یافتشده در عمق بیشتری از زنجیره را بهروزرسانی کند، آسان است:
class DeepChainMap(ChainMap): 'Variant of ChainMap that allows direct updates to inner scopes' def __setitem__(self, key, value): for mapping in self.maps: if key in mapping: mapping[key] = value return self.maps[0][key] = value def __delitem__(self, key): for mapping in self.maps: if key in mapping: del mapping[key] return raise KeyError(key) >>> d = DeepChainMap({'zebra': 'black'}, {'elephant': 'blue'}, {'lion': 'yellow'}) >>> d['lion'] = 'orange' # update an existing key two levels down >>> d['snake'] = 'red' # new keys get added to the topmost dict >>> del d['elephant'] # remove an existing key one level down >>> d # display result DeepChainMap({'zebra': 'black', 'snake': 'red'}, {}, {'lion': 'orange'})
Counter¶یک ابزار شمارنده برای پشتیبانی از شمارشهای آسان و سریع فراهم شده است. برای مثال:
>>> # Tally occurrences of words in a list >>> cnt = Counter() >>> for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']: ... cnt[word] += 1 ... >>> cnt Counter({'blue': 3, 'red': 2, 'green': 1}) >>> # Find the ten most common words in Hamlet >>> import re >>> words = re.findall(r'\w+', open('hamlet.txt').read().lower()) >>> Counter(words).most_common(10) [('the', 1143), ('and', 966), ('to', 762), ('of', 669), ('i', 631), ('you', 554), ('a', 546), ('my', 514), ('hamlet', 471), ('in', 451)]
یک Counter زیرکلاسی از dict برای شمارش اشیای hashable است. این مجموعهای است که در آن عناصر بهعنوان کلیدهای دیکشنری ذخیره میشوند و تعداد آنها بهعنوان مقادیر دیکشنری ذخیره میشود. تعدادها میتوانند هر مقدار عدد صحیحی باشند، از جمله صفر یا تعدادهای منفی. کلاس Counter مشابه کیسهها (bags) یا چندمجموعهها (multisets) در زبانهای دیگر است.
عناصر از یک پیمایشپذیر شمارش میشوند یا از یک نگاشت (یا شمارنده) دیگر مقداردهی اولیه میشوند:
>>> c = Counter() # a new, empty counter >>> c = Counter('gallahad') # a new counter from an iterable >>> c = Counter({'red': 4, 'blue': 2}) # a new counter from a mapping >>> c = Counter(cats=4, dogs=8) # a new counter from keyword args
اشیای Counter یک رابط دیکشنری دارند، با این تفاوت که برای آیتمهای ناموجود، بهجای پرتاب KeyError، شمارش صفر برمیگردانند:
>>> c = Counter(['eggs', 'ham']) >>> c['bacon'] # count of a missing element is zero 0
تنظیم یک شمارش روی صفر، یک عنصر را از شمارنده حذف نمیکند. برای حذف کامل آن از del استفاده کنید:
>>> c['sausage'] = 0 # counter entry with a zero count >>> del c['sausage'] # del actually removes the entry
اضافه شده در نسخهی 3.1.
تغییر یافته در نسخهی 3.7: بهعنوان یک زیرکلاس از dict، Counter قابلیت بهخاطر سپردن ترتیب درج را به ارث برده است. عملیاتهای ریاضی روی اشیای Counter نیز ترتیب را حفظ میکنند. نتایج بر اساس نخستین زمان مواجهه با هر عنصر در عملوند چپ و سپس بر اساس ترتیب مواجهه در عملوند راست مرتب میشوند.
اشیای Counter علاوه بر متدهای در دسترس برای همه دیکشنریها، از متدهای اضافی نیز پشتیبانی میکنند:
یک پیمایشگر بر روی عناصر برمیگرداند که هر عنصر را به تعداد آن تکرار میکند. عناصر به ترتیبی که برای اولین بار مشاهده شدهاند برگردانده میشوند. اگر تعداد یک عنصر کمتر از ۱ باشد، elements() آن را نادیده میگیرد.
>>> c = Counter(a=4, b=2, c=0, d=-2) >>> sorted(c.elements()) ['a', 'a', 'a', 'a', 'b', 'b']
فهرستی از رایجترین n عنصر و تعداد آنها را از رایجترین به کمترین برمیگرداند. اگر n حذف شود یا None باشد، most_common() تمام عناصر موجود در شمارنده را برمیگرداند. عناصری که تعداد برابر دارند، به ترتیبی که برای اولین بار مشاهده شدهاند مرتب میشوند:
>>> Counter('abracadabra').most_common(3) [('a', 5), ('b', 2), ('r', 2)]
عناصر از یک پیمایشپذیر یا از یک نگاشت دیگر (یا شمارنده) کم میشوند. مانند dict.update() است، اما بهجای جایگزینی شمارشها، آنها را کم میکند. هم ورودیها و هم خروجیها میتوانند صفر یا منفی باشند.
>>> c = Counter(a=4, b=2, c=0, d=-2) >>> d = Counter(a=1, b=2, c=3, d=4) >>> c.subtract(d) >>> c Counter({'a': 3, 'b': 0, 'c': -3, 'd': -6})
اضافه شده در نسخهی 3.2.
مجموع شمارشها را محاسبه کنید.
>>> c = Counter(a=10, b=5, c=0) >>> c.total() 15
اضافه شده در نسخهی 3.10.
متدهای معمولی دیکشنری برای اشیای Counter در دسترس هستند، به جز این دو مورد که برای شمارندهها به شکل متفاوتی کار میکنند:
المانها از یک پیمایشپذیر شمرده میشوند یا از یک نگاشت (یا شمارنده) دیگر افزوده میشوند. مانند dict.update() است، اما بهجای جایگزین کردن شمارشها، آنها را میافزاید. همچنین، انتظار میرود پیمایشپذیر دنبالهای از المانها باشد، نه دنبالهای از جفتهای (key, value).
شمارندهها از عملگرهای مقایسهای غنی برای روابط برابری، زیرمجموعه و ابرمجموعه پشتیبانی میکنند: ==، !=، <، <=، >، >=. همهی این مقایسهها عناصر ناموجود را دارای تعداد صفر در نظر میگیرند، بهطوری که Counter(a=1) == Counter(a=1, b=0) مقدار درست برمیگرداند.
تغییر یافته در نسخهی 3.10: عملیاتهای مقایسه غنی افزوده شدند.
تغییر یافته در نسخهی 3.10: در آزمونهای برابری، عناصر غایب بهعنوان دارای تعداد صفر در نظر گرفته میشوند. پیش از این، Counter(a=3) و Counter(a=3, b=0) متمایز در نظر گرفته میشدند.
الگوهای رایج برای کار با اشیای Counter:
c.total() # total of all counts c.clear() # reset all counts list(c) # list unique elements set(c) # convert to a set dict(c) # convert to a regular dictionary c.items() # access the (elem, cnt) pairs Counter(dict(list_of_pairs)) # convert from a list of (elem, cnt) pairs c.most_common()[:-n-1:-1] # n least common elements +c # remove zero and negative counts
چندین عملیات ریاضی برای ترکیب اشیای Counter جهت تولید چندمجموعهها (شمارندههایی که تعدادشان بیشتر از صفر است) ارائه شده است. جمع و تفریق، شمارندهها را با اضافه کردن یا کم کردن تعداد عناصر متناظر ترکیب میکنند. اشتراک و اجتماع، حداقل و حداکثر تعدادهای متناظر را برمیگردانند. تفاضل تقارنی، اختلاف بین حداکثر و حداقل تعدادهای متناظر را برمیگرداند. برابری و شمول، تعدادهای متناظر را مقایسه میکنند. هر عملیات میتواند ورودیهایی با تعدادهای علامتدار بپذیرد، اما خروجی نتایج با تعدادهای صفر یا کمتر را حذف خواهد کرد.
>>> c = Counter(a=3, b=1) >>> d = Counter(a=1, b=2) >>> c + d # add two counters together: c[x] + d[x] Counter({'a': 4, 'b': 3}) >>> c - d # subtract (keeping only positive counts) Counter({'a': 2}) >>> c & d # intersection: min(c[x], d[x]) Counter({'a': 1, 'b': 1}) >>> c | d # union: max(c[x], d[x]) Counter({'a': 3, 'b': 2}) >>> c ^ d # max(c[x], d[x]) - min(c[x], d[x]) Counter({'a': 2, 'b': 1}) >>> c == d # equality: c[x] == d[x] False >>> c <= d # inclusion: c[x] <= d[x] False
جمع و تفریق یکعملوندی، میانبرهایی برای افزودن یک شمارنده خالی یا کم کردن از یک شمارنده خالی هستند.
>>> c = Counter(a=2, b=-4) >>> +c Counter({'a': 2}) >>> -c Counter({'b': 4})
اضافه شده در نسخهی 3.3: پشتیبانی از عملگرهای یکعملوندی مثبت و منفی و عملیاتهای چندمجموعهای درجا افزوده شد.
اضافه شده در نسخهی 3.15: پشتیبانی از عملیات چندمجموعهای تفاضل تقارنی، یعنی c ^ d اضافه شد.
نکته
شمارندهها عمدتاً برای کار با اعداد صحیح مثبت به منظور نمایش شمارشهای جاری طراحی شدهاند؛ با این حال، دقت شده است که بهطور غیرضروری از موارد استفادهای که نیازمند انواع دیگر یا مقادیر منفی هستند جلوگیری نشود. برای کمک به این موارد استفاده، این بخش حداقل دامنه و محدودیتهای نوع را مستند میکند.
خود کلاس Counter زیرکلاسی از دیکشنری است و هیچ محدودیتی روی کلیدها و مقادیر آن ندارد. مقادیر در نظر گرفته شدهاند که اعدادی برای نمایش شمارشها باشند، اما شما میتوانید هر چیزی را در فیلد مقدار ذخیره کنید.
متد most_common() تنها نیاز دارد که مقادیر قابل مرتبسازی باشند.
برای عملیاتهای درجا مانند c[key] += 1، نوع مقدار فقط باید از جمع و تفریق پشتیبانی کند. بنابراین کسرها، اعداد اعشاری و اعداد صحیح قابل استفاده هستند و مقادیر منفی نیز پشتیبانی میشوند. همین موضوع برای update() و subtract() نیز صادق است، که مقادیر منفی و صفر را برای هر دو ورودی و خروجی میپذیرند.
متدهای چندمجموعه فقط برای موارد استفاده با مقادیر مثبت طراحی شدهاند. ورودیها ممکن است منفی یا صفر باشند، اما فقط خروجیهایی با مقادیر مثبت ایجاد میشوند. هیچ محدودیت نوعی وجود ندارد، اما نوع مقدار باید از جمع، تفریق و مقایسه پشتیبانی کند.
متد elements() به شمارشهای عدد صحیح نیاز دارد. این متد شمارشهای صفر و منفی را نادیده میگیرد.
همچنین ببینید
کلاس Bag در Smalltalk.
مدخل ویکیپدیا برای چندمجموعهها.
آموزش چندمجموعههای C++ همراه با مثالها.
برای عملیات ریاضی بر روی چندمجموعهها و موارد استفادهی آنها، Knuth, Donald. The Art of Computer Programming Volume II, Section 4.6.3, Exercise 19 را ببینید.
برای برشمردن تمام چندمجموعههای متمایز با اندازهی مشخص بر روی یک مجموعهی مشخص از عناصر، itertools.combinations_with_replacement() را ببینید:
map(Counter, combinations_with_replacement('ABC', 2)) # --> AA AB AC BB BC CC
deque¶یک شیء deque جدید بازمیگرداند که از چپ به راست (با استفاده از append()) با دادههای iterable مقداردهی اولیه شده است. اگر iterable مشخص نشده باشد، deque جدید خالی است.
صفهای دوطرفه (deque) تعمیمی از پشتهها و صفها هستند (این نام بهصورت «deck» تلفظ میشود و کوتاهشدهی «double-ended queue» است). صفهای دوطرفه از افزودن و برداشتن ایمن برای نخها و کارآمد از نظر حافظه از هر طرف صف دوطرفه، با کارایی تقریباً یکسان O(1) در هر جهت پشتیبانی میکنند.
اگرچه اشیای list از عملیات مشابهی پشتیبانی میکنند، اما برای عملیات سریع با طول ثابت بهینهسازی شدهاند و برای عملیات pop(0) و insert(0, v) که هم اندازه و هم موقعیت نمایش دادههای زیرین را تغییر میدهند، مستلزم هزینههای جابهجایی حافظه با مرتبهی O(n) هستند.
اگر maxlen مشخص نشده باشد یا None باشد، صفهای دوطرفه (deque) میتوانند تا طول دلخواهی رشد کنند. در غیر این صورت، صف دوطرفه به حداکثر طول مشخصشده محدود میشود. هنگامی که یک صف دوطرفه با طول محدود پر شد، با افزودن آیتمهای جدید، تعداد متناظری از آیتمها از سمت مخالف دور ریخته میشوند. صفهای دوطرفه با طول محدود، عملکردی مشابه فیلتر tail در Unix ارائه میدهند. آنها همچنین برای پیگیری تراکنشها و سایر مخازن دادهای که تنها جدیدترین فعالیت مورد توجه است، مفید هستند.
صفهای دوطرفه (deque) نسبت به نوع محتوای خود عام هستند.
اشیای Deque از متدهای زیر پشتیبانی میکنند:
item را به سمت راست deque میافزاید.
item را به سمت چپ deque اضافه کنید.
همهی عناصر را از صف دوطرفه (deque) حذف میکند و طول آن را به ۰ میرساند.
یک کپی سطحی از deque ایجاد میکند.
اضافه شده در نسخهی 3.5.
تعداد عناصر deque برابر با value را میشمارد.
اضافه شده در نسخهی 3.2.
سمت راست deque را با افزودن المانها از آرگومان پیمایشپذیر گسترش دهید.
سمت چپ صف دوطرفه (deque) را با الحاق عناصری از iterable گسترش دهید. توجه داشته باشید که دنبالهی الحاقهای سمت چپ، باعث معکوس شدن ترتیب عناصر در آرگومان پیمایشپذیر میشود.
موقعیت value را در صف دوطرفه (deque) برمیگرداند (در اندیس start یا پس از آن و پیش از اندیس stop). نخستین تطابق را برمیگرداند یا در صورت پیدا نشدن، ValueError را پرتاب میکند.
اضافه شده در نسخهی 3.5.
value را در موقعیت index در صف دوطرفه (deque) درج کنید.
اگر درج موجب شود که یک deque کراندار بزرگتر از maxlen شود، یک IndexError پرتاب میشود.
اضافه شده در نسخهی 3.5.
یک المان را از سمت راست deque حذف کرده و برمیگرداند. اگر هیچ المانی وجود نداشته باشد، یک IndexError پرتاب میشود.
یک عنصر را از سمت چپ deque حذف میکند و آن را برمیگرداند. اگر هیچ عنصری وجود نداشته باشد، یک IndexError پرتاب میشود.
اولین رخداد value را حذف میکند. اگر پیدا نشد، یک ValueError پرتاب میکند.
عناصر deque را بهصورت درجا معکوس میکند و سپس None را برمیگرداند.
اضافه شده در نسخهی 3.2.
deque را n گام به راست بچرخانید. اگر n منفی باشد، به چپ بچرخانید.
هنگامی که deque خالی نیست، چرخاندن یک گام به راست معادل d.appendleft(d.pop()) است، و چرخاندن یک گام به چپ معادل d.append(d.popleft()) است.
اشیای Deque همچنین یک ویژگی فقطخواندنی ارائه میدهند:
حداکثر اندازهی یک deque یا None در صورت نامحدود بودن.
اضافه شده در نسخهی 3.1.
علاوه بر موارد بالا، صفهای دوطرفه (deques) از تکرار، پیکلکردن، len(d)، reversed(d)، copy.copy(d)، copy.deepcopy(d)، بررسی عضویت با عملگر in، و ارجاعهای اندیسی مانند d[0] برای دسترسی به اولین عنصر پشتیبانی میکنند. دسترسی اندیسی در هر دو انتها O(1) است، اما در میانه به O(n) کند میشود. برای دسترسی تصادفی سریع، بهجای آن از فهرستها استفاده کنید.
از نسخه 3.5 به بعد، صفهای دوطرفه (deque) از __add__()، __mul__() و __imul__() پشتیبانی میکنند.
مثال:
>>> from collections import deque >>> d = deque('ghi') # make a new deque with three items >>> for elem in d: # iterate over the deque's elements ... print(elem.upper()) G H I >>> d.append('j') # add a new entry to the right side >>> d.appendleft('f') # add a new entry to the left side >>> d # show the representation of the deque deque(['f', 'g', 'h', 'i', 'j']) >>> d.pop() # return and remove the rightmost item 'j' >>> d.popleft() # return and remove the leftmost item 'f' >>> list(d) # list the contents of the deque ['g', 'h', 'i'] >>> d[0] # peek at leftmost item 'g' >>> d[-1] # peek at rightmost item 'i' >>> list(reversed(d)) # list the contents of a deque in reverse ['i', 'h', 'g'] >>> 'h' in d # search the deque True >>> d.extend('jkl') # add multiple elements at once >>> d deque(['g', 'h', 'i', 'j', 'k', 'l']) >>> d.rotate(1) # right rotation >>> d deque(['l', 'g', 'h', 'i', 'j', 'k']) >>> d.rotate(-1) # left rotation >>> d deque(['g', 'h', 'i', 'j', 'k', 'l']) >>> deque(reversed(d)) # make a new deque in reverse order deque(['l', 'k', 'j', 'i', 'h', 'g']) >>> d.clear() # empty the deque >>> d.pop() # cannot pop from an empty deque Traceback (most recent call last): File "<pyshell#6>", line 1, in -toplevel- d.pop() IndexError: pop from an empty deque >>> d.extendleft('abc') # extendleft() reverses the input order >>> d deque(['c', 'b', 'a'])
deque¶این بخش روشهای مختلفی را برای کار با صفهای دوطرفه (deque) نشان میدهد.
صفهای دوطرفه (deque) با طول محدود، عملکردی مشابه فیلتر tail در یونیکس فراهم میکنند:
def tail(filename, n=10): 'Return the last n lines of a file' with open(filename) as f: return deque(f, n)
رویکرد دیگر برای استفاده از صفهای دوطرفه (deque)، نگهداری دنبالهای از المانهای بهتازگی اضافهشده با افزودن به راست و برداشتن از چپ است:
def moving_average(iterable, n=3): # moving_average([40, 30, 50, 46, 39, 44]) --> 40.0 42.0 45.0 43.0 # https://en.wikipedia.org/wiki/Moving_average it = iter(iterable) d = deque(itertools.islice(it, n-1)) d.appendleft(0) s = sum(d) for elem in it: s += elem - d.popleft() d.append(elem) yield s / n
یک زمانبندی چرخشی میتواند با پیمایشگرهای ورودی که در یک deque ذخیره شدهاند پیادهسازی شود. مقادیر از پیمایشگر فعال در موقعیت صفر تولید میشوند. اگر آن پیمایشگر اتمامیافته باشد، میتواند با popleft() حذف شود؛ در غیر این صورت، میتواند با متد rotate() به انتهای چرخه بازگردانده شود:
def roundrobin(*iterables): "roundrobin('ABC', 'D', 'EF') --> A D E B F C" iterators = deque(map(iter, iterables)) while iterators: try: while True: yield next(iterators[0]) iterators.rotate(-1) except StopIteration: # Remove an exhausted iterator. iterators.popleft()
متد rotate() راهی برای پیادهسازی اسلایس و حذف deque فراهم میکند. برای مثال، یک پیادهسازی پایتون خالص از del d[n] برای قرار دادن عناصر در موقعیت مناسب جهت خارج کردن، به متد rotate() متکی است:
def delete_nth(d, n): d.rotate(-n) d.popleft() d.rotate(n)
برای پیادهسازی اسلایس deque، از رویکرد مشابهی با اعمال rotate() استفاده کنید تا یک عنصر هدف به سمت چپ deque برسد. آیتمهای قدیمی را با popleft() حذف کنید، آیتمهای جدید را با extend() اضافه کنید و سپس چرخش را معکوس کنید. با تغییرات جزئی در این رویکرد، پیادهسازی دستکاریهای پشته به سبک Forth مانند dup، drop، swap، over، pick، rot و roll آسان است.
defaultdict¶یک شیء دیکشنریمانند جدید برمیگرداند. defaultdict زیرکلاسی از کلاس توکار dict است. این کلاس یک متد را بازتعریف میکند و یک متغیر نمونه قابلنوشتن اضافه میکند. سایر قابلیتها مانند کلاس dict هستند و در اینجا مستند نشدهاند.
نخستین آرگومان مقدار اولیهی ویژگی default_factory را فراهم میکند؛ مقدار پیشفرض آن None است. با تمام آرگومانهای باقیمانده همانگونه رفتار میشود که گویی به سازندهی dict ارسال شده باشند، از جمله آرگومانهای کلیدواژهای.
defaultdictها نسبت به دو نوع عام هستند که (بهترتیب) بیانگر انواع کلیدها و مقادیر دیکشنری هستند.
اشیای defaultdict علاوه بر عملیات استاندارد dict، از متد زیر نیز پشتیبانی میکنند:
اگر ویژگی default_factory برابر None باشد، این عمل یک استثنای KeyError را با key بهعنوان آرگومان پرتاب میکند.
اگر default_factory برابر None نباشد، بدون آرگومان فراخوانی میشود تا مقدار پیشفرضی برای کلید دادهشده فراهم کند؛ این مقدار در دیکشنری برای کلید درج میشود و برگردانده میشود.
اگر فراخوانی default_factory باعث پرتاب استثنایی شود، این استثنا بدون تغییر انتشار مییابد.
این متد توسط متد __getitem__() از کلاس dict زمانی فراخوانی میشود که کلید درخواستشده یافت نشود؛ هر آنچه برگرداند یا پرتاب کند، سپس توسط __getitem__() برگردانده یا پرتاب میشود.
توجه داشته باشید که __missing__() برای هیچ عملیاتی به جز __getitem__() فراخوانی نمیشود. این بدان معناست که get() مانند دیکشنریهای معمولی، به جای استفاده از default_factory، None را بهعنوان مقدار پیشفرض برمیگرداند.
اشیای defaultdict از متغیر نمونهی زیر پشتیبانی میکنند:
این ویژگی توسط متد __missing__() استفاده میشود؛ در صورت وجود اولین آرگومان سازنده، از آن مقداردهی اولیه میشود و در غیر این صورت به None مقداردهی اولیه میشود.
تغییر یافته در نسخهی 3.9: عملگرهای ادغام (|) و بهروزرسانی (|=)، مشخصشده در PEP 584، افزوده شدند.
defaultdict¶با استفاده از list بهعنوان default_factory، بهآسانی میتوان دنبالهای از جفتهای کلید-مقدار را در یک دیکشنری از فهرستها گروهبندی کرد:
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)] >>> d = defaultdict(list) >>> for k, v in s: ... d[k].append(v) ... >>> sorted(d.items()) [('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
هنگامی که هر کلید برای نخستین بار مشاهده میشود، از قبل در نگاشت وجود ندارد؛ بنابراین یک آیتم بهطور خودکار با استفاده از تابع default_factory ایجاد میشود که یک list خالی برمیگرداند. سپس عملیات list.append() مقدار را به فهرست جدید اضافه میکند. هنگامی که کلیدها دوباره مشاهده میشوند، جستوجو بهطور عادی انجام میشود (فهرست مربوط به آن کلید را برمیگرداند) و عملیات list.append() مقدار دیگری را به فهرست اضافه میکند. این روش سادهتر و سریعتر از روش معادلی است که از dict.setdefault() استفاده میکند:
>>> d = {} >>> for k, v in s: ... d.setdefault(k, []).append(v) ... >>> sorted(d.items()) [('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
با تنظیم default_factory روی int، defaultdict برای شمارش مفید میشود (مانند bag یا multiset در زبانهای دیگر):
>>> s = 'mississippi' >>> d = defaultdict(int) >>> for k in s: ... d[k] += 1 ... >>> sorted(d.items()) [('i', 4), ('m', 1), ('p', 2), ('s', 4)]
هنگامی که برای نخستین بار با حرفی مواجه میشوید، آن حرف در نگاشت وجود ندارد، بنابراین تابع default_factory، تابع int() را فراخوانی میکند تا یک شمارش پیشفرض برابر با صفر فراهم کند. سپس عملیات افزایش، شمارش هر حرف را بهتدریج افزایش میدهد.
تابع int() که همیشه صفر را برمیگرداند، تنها حالت خاصی از توابع ثابت است. راهی سریعتر و انعطافپذیرتر برای ایجاد توابع ثابت، استفاده از یک تابع لامبدا است که میتواند هر مقدار ثابتی را ارائه کند (نه فقط صفر):
>>> def constant_factory(value): ... return lambda: value ... >>> d = defaultdict(constant_factory('<missing>')) >>> d.update(name='John', action='ran') >>> '%(name)s %(action)s to %(object)s' % d 'John ran to <missing>'
با تنظیم default_factory روی set، defaultdict برای ساختن یک دیکشنری از مجموعهها مفید میشود:
>>> s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)] >>> d = defaultdict(set) >>> for k, v in s: ... d[k].add(v) ... >>> sorted(d.items()) [('blue', {2, 4}), ('red', {1, 3})]
namedtuple() تابع کارخانه برای تاپلهای دارای فیلدهای نامدار¶تاپلهای نامدار به هر جایگاه در یک تاپل معنا میبخشند و امکان کدی خواناتر و خودمستند را فراهم میکنند. این تاپلها میتوانند هر جا که تاپلهای معمولی استفاده میشوند، به کار روند و توانایی دسترسی به فیلدها از طریق نام بهجای اندیس جایگاه را اضافه کنند.
یک زیرکلاس جدید از تاپل به نام typename برمیگرداند. زیرکلاس جدید برای ایجاد اشیایی شبیه به تاپل به کار میرود که فیلدهایی قابل دسترسی از طریق جستوجوی ویژگی دارند و همچنین قابل اندیسگذاری و پیمایشپذیر هستند. نمونههای این زیرکلاس همچنین یک رشته مستند مفید (شامل typename و field_names) و یک متد مفید __repr__() دارند که محتویات تاپل را در قالب name=value فهرست میکند.
field_names دنبالهای از رشتهها مانند ['x', 'y'] است. بهعنوان جایگزین، field_names میتواند یک رشته واحد باشد که در آن هر نام فیلد با فضای خالی و/یا کاما جدا شده باشد، برای مثال 'x y' یا 'x, y'.
هر شناسه معتبر پایتون را میتوان برای نام فیلد به کار برد، بهجز نامهایی که با زیرخط شروع میشوند. شناسههای معتبر از حروف، ارقام و زیرخط تشکیل میشوند، اما با رقم یا زیرخط شروع نمیشوند و نمیتوانند یک keyword مانند class، for، return، global، pass یا raise باشند.
اگر rename مقدار true داشته باشد، نامهای فیلد نامعتبر بهطور خودکار با نامهای جایگاهی جایگزین میشوند. برای مثال، ['abc', 'def', 'ghi', 'abc'] به ['abc', '_1', 'ghi', '_3'] تبدیل میشود و کلیدواژه def و نام فیلد تکراری abc حذف میشوند.
defaults میتواند None یا یک پیمایشپذیر از مقادیر پیشفرض باشد. از آنجا که فیلدهای دارای مقدار پیشفرض باید بعد از فیلدهای بدون مقدار پیشفرض بیایند، defaults به راستترین پارامترها اعمال میشود. برای مثال، اگر نام فیلدها ['x', 'y', 'z'] و مقادیر پیشفرض (1, 2) باشند، x یک آرگومان ضروری خواهد بود، مقدار پیشفرض y برابر 1 خواهد بود، و مقدار پیشفرض z برابر 2 خواهد بود.
اگر module تعریف شده باشد، ویژگی __module__ تاپل نامدار (named tuple) برابر آن مقدار قرار میگیرد.
نمونههای تاپل نامدار، دیکشنریهای بهازای هر نمونه ندارند، بنابراین سبک هستند و به حافظه بیشتری نسبت به تاپلهای معمولی نیاز ندارند.
برای پشتیبانی از پیکلکردن، کلاس تاپل نامدار (named tuple) باید به متغیری اختصاص داده شود که با typename مطابقت داشته باشد.
تغییر یافته در نسخهی 3.1: پشتیبانی از rename افزوده شد.
تغییر یافته در نسخهی 3.6: پارامترهای verbose و rename به آرگومانهای فقط کلیدواژهای تبدیل شدند.
تغییر یافته در نسخهی 3.6: پارامتر module اضافه شد.
تغییر یافته در نسخهی 3.7: پارامتر verbose و ویژگی _source حذف شدند.
تغییر یافته در نسخهی 3.7: پارامتر defaults و ویژگی _field_defaults اضافه شد.
>>> # Basic example >>> Point = namedtuple('Point', ['x', 'y']) >>> p = Point(11, y=22) # instantiate with positional or keyword arguments >>> p[0] + p[1] # indexable like the plain tuple (11, 22) 33 >>> x, y = p # unpack like a regular tuple >>> x, y (11, 22) >>> p.x + p.y # fields also accessible by name 33 >>> p # readable __repr__ with a name=value style Point(x=11, y=22)
تاپلهای نامدار بهویژه برای اختصاص نامهای فیلد به تاپلهای نتیجهای که از ماژولهای csv یا sqlite3 بازگردانده میشوند، مفید هستند:
EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade') import csv for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "rb"))): print(emp.name, emp.title) import sqlite3 conn = sqlite3.connect('/companydata') cursor = conn.cursor() cursor.execute('SELECT name, age, title, department, paygrade FROM employees') for emp in map(EmployeeRecord._make, cursor.fetchall()): print(emp.name, emp.title)
علاوه بر متدهای به ارث بردهشده از تاپلها، تاپلهای نامدار از سه متد و دو ویژگی اضافی پشتیبانی میکنند. برای جلوگیری از تداخل با نام فیلدها، نام متدها و ویژگیها با یک زیرخط شروع میشوند.
متد کلاسی که یک نمونه جدید را از یک دنباله یا پیمایشپذیر موجود میسازد.
>>> t = [11, 22] >>> Point._make(t) Point(x=11, y=22)
یک dict جدید برمیگرداند که نام فیلدها را به مقادیر متناظر آنها نگاشت میکند:
>>> p = Point(x=11, y=22) >>> p._asdict() {'x': 11, 'y': 22}
تغییر یافته در نسخهی 3.1: یک OrderedDict بهجای یک dict معمولی برمیگرداند.
تغییر یافته در نسخهی 3.8: یک dict معمولی را بهجای یک OrderedDict بازمیگرداند. از پایتون 3.7 به بعد، ترتیب دیکشنریهای معمولی تضمین شده است. اگر امکانات اضافی OrderedDict مورد نیاز باشد، راهحل پیشنهادی، تبدیل نتیجه به نوع دلخواه است: OrderedDict(nt._asdict()).
یک نمونه جدید از تاپل نامدار (named tuple) برمیگرداند که در آن فیلدهای مشخصشده با مقدارهای جدید جایگزین شدهاند:
>>> p = Point(x=11, y=22) >>> p._replace(x=33) Point(x=33, y=22) >>> for partnum, record in inventory.items(): ... inventory[partnum] = record._replace(price=newprices[partnum], timestamp=time.now())
تابع عام copy.replace() نیز از تاپلهای نامدار (named tuples) پشتیبانی میکند.
تغییر یافته در نسخهی 3.13: برای آرگومانهای کلیدواژهای نامعتبر، بهجای ValueError، TypeError ایجاد میکند.
تاپلی از رشتهها که نام فیلدها را فهرست میکند. برای دروننگری و ایجاد انواع جدیدی از تاپلهای نامدار از تاپلهای نامدار موجود مفید است.
>>> p._fields # view the field names ('x', 'y') >>> Color = namedtuple('Color', 'red green blue') >>> Pixel = namedtuple('Pixel', Point._fields + Color._fields) >>> Pixel(11, 22, 128, 255, 0) Pixel(x=11, y=22, red=128, green=255, blue=0)
دیکشنریای که نام فیلدها را به مقادیر پیشفرض نگاشت میکند.
>>> Account = namedtuple('Account', ['type', 'balance'], defaults=[0]) >>> Account._field_defaults {'balance': 0} >>> Account('premium') Account(type='premium', balance=0)
برای بازیابی فیلدی که نام آن در یک رشته ذخیرهشده است، از تابع getattr() استفاده کنید:
>>> getattr(p, 'x') 11
برای تبدیل یک دیکشنری به یک تاپل نامدار (named tuple)، از عملگر دو ستارهای (double-star-operator) استفاده کنید (همانطور که در واگشایی آرگومانها توضیح داده شده است):
>>> d = {'x': 11, 'y': 22} >>> Point(**d) Point(x=11, y=22)
از آنجا که تاپل نامدار (named tuple) یک کلاس معمولی پایتون است، افزودن یا تغییر قابلیت با یک زیرکلاس آسان است. در اینجا نحوه افزودن یک فیلد محاسبهشده و یک قالب چاپ با عرض ثابت آمده است:
>>> class Point(namedtuple('Point', ['x', 'y'])): ... __slots__ = () ... @property ... def hypot(self): ... return (self.x ** 2 + self.y ** 2) ** 0.5 ... def __str__(self): ... return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % (self.x, self.y, self.hypot) >>> for p in Point(3, 4), Point(14, 5/7): ... print(p) Point: x= 3.000 y= 4.000 hypot= 5.000 Point: x=14.000 y= 0.714 hypot=14.018
زیرکلاسی که در بالا نشان داده شد، __slots__ را برابر با یک تاپل خالی قرار میدهد. این کار با جلوگیری از ایجاد دیکشنریهای نمونهها، به پایین نگه داشتن میزان حافظه مورد نیاز کمک میکند.
زیرکلاسسازی برای افزودن فیلدهای ذخیرهشدهی جدید مفید نیست. در عوض، بهسادگی یک نوع جدید named tuple از ویژگی _fields ایجاد کنید:
>>> Point3D = namedtuple('Point3D', Point._fields + ('z',))
میتوانید رشته مستندات را با انتساب مستقیم به فیلدهای __doc__ سفارشی کنید:
>>> Book = namedtuple('Book', ['id', 'title', 'authors']) >>> Book.__doc__ += ': Hardcover book in active collection' >>> Book.id.__doc__ = '13-digit ISBN' >>> Book.title.__doc__ = 'Title of first printing' >>> Book.authors.__doc__ = 'List of authors sorted by last name'
تغییر یافته در نسخهی 3.5: رشتهمستندهای پراپرتی قابلنوشتن شدند.
همچنین ببینید
برای روشی جهت افزودن راهنمای نوع به تاپلهای نامدار، typing.NamedTuple را ببینید. این کلاس همچنین یک نمادگذاری آراسته با استفاده از کلیدواژهی class ارائه میکند:
class Component(NamedTuple): part_number: int weight: float description: Optional[str] = None
برای یک فضای نام تغییرپذیر که بهجای یک تاپل، مبتنی بر یک دیکشنری زیربنایی است، types.SimpleNamespace() را ببینید.
ماژول dataclasses یک دکوراتور و توابعی را برای افزودن خودکار متدهای ویژهی تولیدشده به کلاسهای تعریفشده توسط کاربر فراهم میکند.
OrderedDict¶دیکشنریهای ترتیبدار دقیقاً مانند دیکشنریهای معمولی هستند، اما قابلیتهای اضافی مربوط به عملیات ترتیبدهی دارند. اکنون که کلاس توکار dict توانایی بهخاطر سپردن ترتیب درج را به دست آورده است، اهمیت کمتری یافتهاند (این رفتار جدید در Python 3.7 تضمین شد).
هنوز برخی تفاوتها با dict باقی ماندهاند:
dict معمولی طراحی شده است تا در عملیات نگاشت بسیار کارآمد باشد. پیگیری ترتیب درج، اولویت دوم بود.
OrderedDict بهگونهای طراحی شده بود که در عملیات تغییر ترتیب عملکرد خوبی داشته باشد. کارایی فضایی، سرعت پیمایش و عملکرد عملیات بهروزرسانی در درجه دوم اهمیت قرار داشتند.
الگوریتم OrderedDict میتواند عملیات مکرر بازچینش را بهتر از dict مدیریت کند. همانطور که در دستورات زیر نشان داده شده است، این امر آن را برای پیادهسازی انواع مختلفی از نهانگاههای LRU مناسب میسازد.
عملیات برابری برای OrderedDict یکسان بودن ترتیب را بررسی میکند.
یک dict معمولی میتواند آزمون برابری حساس به ترتیب را با p == q and all(k1 == k2 for k1, k2 in zip(p, q)) شبیهسازی کند.
متد popitem() در OrderedDict امضای متفاوتی دارد. این متد یک آرگومان اختیاری میپذیرد تا مشخص کند کدام آیتم خارج میشود.
یک dict معمولی میتواند od.popitem(last=True) مربوط به OrderedDict را با d.popitem() شبیهسازی کند، که تضمین میشود آیتم سمت راست (آخرین آیتم) را خارج کند.
یک dict معمولی میتواند od.popitem(last=False) مربوط به OrderedDict را با (k := next(iter(d)), d.pop(k)) شبیهسازی کند، که چپترین (نخستین) آیتم را در صورت وجود برمیگرداند و حذف میکند.
OrderedDict یک متد move_to_end() برای جابهجایی کارآمد یک عنصر به یک پایانه دارد.
یک dict معمولی میتواند od.move_to_end(k, last=True) در OrderedDict را با d[k] = d.pop(k) شبیهسازی کند، که کلید و مقدار مرتبط با آن را به جایگاه انتهایی (آخرین) منتقل میکند.
یک dict معمولی معادل کارآمدی برای od.move_to_end(k, last=False) در OrderedDict ندارد که کلید و مقدار مرتبط با آن را به چپترین (اولین) جایگاه منتقل میکند.
تا پیش از پایتون 3.8، dict فاقد متد __reversed__() بود.
نمونهای از یک زیرکلاس dict برمیگرداند که دارای متدهایی اختصاصی برای بازآرایی ترتیب دیکشنری است.
اضافه شده در نسخهی 3.1.
متد popitem() برای دیکشنریهای ترتیبدار یک جفت (کلید، مقدار) را برمیگرداند و حذف میکند. اگر last درست باشد، جفتها به ترتیب LIFO و اگر نادرست باشد، به ترتیب FIFO برگردانده میشوند.
یک key موجود را به یکی از دو انتهای یک دیکشنری ترتیبدار منتقل میکند. اگر last برابر true باشد (پیشفرض)، آیتم به انتهای سمت راست منتقل میشود و اگر last برابر false باشد، به ابتدا منتقل میشود. در صورتی که key وجود نداشته باشد، KeyError پرتاب میشود:
>>> d = OrderedDict.fromkeys('abcde') >>> d.move_to_end('b') >>> ''.join(d) 'acdeb' >>> d.move_to_end('b', last=False) >>> ''.join(d) 'bacde'
اضافه شده در نسخهی 3.2.
علاوه بر متدهای معمول نگاشت، دیکشنریهای ترتیبی نیز از پیمایش معکوس با استفاده از reversed() پشتیبانی میکنند.
آزمونهای برابری میان اشیای OrderedDict به ترتیب حساس هستند و تقریباً معادل list(od1.items())==list(od2.items()) هستند.
آزمونهای برابری بین اشیای OrderedDict و سایر اشیای Mapping مانند دیکشنریهای معمولی، نسبت به ترتیب حساس نیستند. این امر امکان میدهد که اشیای OrderedDict در هر جایی که از یک دیکشنری معمولی استفاده میشود، جایگزین شوند.
تغییر یافته در نسخهی 3.5: نماهای آیتمها، کلیدها و مقادیر OrderedDict اکنون از پیمایش معکوس با استفاده از reversed() پشتیبانی میکنند.
تغییر یافته در نسخهی 3.6: با پذیرش PEP 468، ترتیب برای آرگومانهای کلیدواژهای ارسالشده به سازندهی OrderedDict و متد update() آن حفظ میشود.
تغییر یافته در نسخهی 3.9: عملگرهای ادغام (|) و بهروزرسانی (|=)، مشخصشده در PEP 584، افزوده شدند.
OrderedDict مثالها و دستورهای پخت¶ایجاد گونهای از دیکشنری مرتب که ترتیب آخرین بار درج کلیدها را به خاطر میآورد، ساده است. اگر یک آیتم جدید، یک آیتم موجود را بازنویسی کند، موقعیت درج اصلی تغییر میکند و به انتها منتقل میشود:
class LastUpdatedOrderedDict(OrderedDict): 'Store items in the order that the keys were last updated.' def __setitem__(self, key, value): super().__setitem__(key, value) self.move_to_end(key)
یک OrderedDict همچنین میتواند برای پیادهسازی انواعی از @functools.lru_cache مفید باشد:
from collections import OrderedDict from time import monotonic class TimeBoundedLRU: "LRU Cache that invalidates and refreshes old entries." def __init__(self, func, maxsize=128, maxage=30): self.cache = OrderedDict() # { args : (timestamp, result)} self.func = func self.maxsize = maxsize self.maxage = maxage def __call__(self, *args): if args in self.cache: self.cache.move_to_end(args) timestamp, result = self.cache[args] if monotonic() - timestamp <= self.maxage: return result result = self.func(*args) self.cache[args] = monotonic(), result if len(self.cache) > self.maxsize: self.cache.popitem(last=False) return result
class MultiHitLRUCache: """ LRU cache that defers caching a result until it has been requested multiple times. To avoid flushing the LRU cache with one-time requests, we don't cache until a request has been made more than once. """ def __init__(self, func, maxsize=128, maxrequests=4096, cache_after=1): self.requests = OrderedDict() # { uncached_key : request_count } self.cache = OrderedDict() # { cached_key : function_result } self.func = func self.maxrequests = maxrequests # max number of uncached requests self.maxsize = maxsize # max number of stored return values self.cache_after = cache_after def __call__(self, *args): if args in self.cache: self.cache.move_to_end(args) return self.cache[args] result = self.func(*args) self.requests[args] = self.requests.get(args, 0) + 1 if self.requests[args] <= self.cache_after: self.requests.move_to_end(args) if len(self.requests) > self.maxrequests: self.requests.popitem(last=False) else: self.requests.pop(args, None) self.cache[args] = result if len(self.cache) > self.maxsize: self.cache.popitem(last=False) return result
UserDict¶کلاس UserDict بهعنوان پوششی برای اشیای دیکشنری عمل میکند. نیاز به این کلاس تا حدی با امکان ایجاد زیرکلاس مستقیماً از dict جایگزین شده است؛ با این حال، کار با این کلاس میتواند آسانتر باشد، زیرا دیکشنری زیرین بهعنوان یک ویژگی قابل دسترسی است.
کلاسی که یک دیکشنری را شبیهسازی میکند. محتویات نمونه در یک دیکشنری معمولی نگهداری میشود، که از طریق ویژگی data نمونههای UserDict قابل دسترسی است. اگر آرگومانهایی ارائه شوند، از آنها برای مقداردهی اولیهی data استفاده میشود، مانند یک دیکشنری معمولی.
علاوه بر پشتیبانی از متدها و عملیات نگاشتها، نمونههای UserDict ویژگی زیر را فراهم میکنند:
نمونههای UserDict همچنین متد زیر را بازنویسی میکنند:
یک جفت (key, value) را از دیکشنری بستهبندیشده حذف کرده و برمیگرداند. جفتها به همان ترتیبی که data.popitem() برمیگرداند، بازگردانده میشوند. (برای dict.popitem() پیشفرض، این ترتیب به صورت LIFO است.) اگر دیکشنری خالی باشد، استثنای KeyError را بالا میآورد.
UserList¶این کلاس بهعنوان پوششی برای اشیای فهرست عمل میکند. این کلاس، کلاس پایه مفیدی برای کلاسهای فهرستمانند خودتان است که میتوانند از آنها ارثبری کنند، متدهای موجود را بازنویسی کنند یا متدهای جدیدی اضافه کنند. به این ترتیب، میتوان رفتارهای جدیدی به فهرستها اضافه کرد.
نیاز به این کلاس تا حدی با امکان زیرکلاسگیری مستقیم از list جایگزین شده است؛ با این حال، کار با این کلاس میتواند آسانتر باشد، زیرا فهرست زیربنایی بهعنوان یک ویژگی قابل دسترسی است.
کلاسی که یک فهرست را شبیهسازی میکند. محتوای نمونه در یک فهرست معمولی نگهداری میشود، که از طریق ویژگی data در نمونههای UserList قابل دسترسی است. محتوای نمونه در ابتدا به یک کپی از list تنظیم میشود، که بهطور پیشفرض فهرست خالی [] است. list میتواند هر پیمایشپذیری باشد، برای مثال یک فهرست واقعی پایتون یا یک شیء UserList.
علاوه بر پشتیبانی از متدها و عملیات دنبالههای تغییرپذیر، نمونههای UserList ویژگی زیر را ارائه میدهند:
الزامات زیرکلاسسازی: انتظار میرود زیرکلاسهای UserList سازندهای ارائه دهند که بتوان آن را بدون آرگومان یا با یک آرگومان فراخوانی کرد. عملیات فهرستی که دنبالهی جدیدی بازمیگردانند، تلاش میکنند نمونهای از کلاس پیادهسازی واقعی ایجاد کنند. برای این کار، فرض میشود که سازنده میتواند با یک پارامتر فراخوانی شود، که یک شیء دنباله است و بهعنوان منبع داده استفاده میشود.
اگر یک کلاس مشتق مایل به رعایت این الزام نباشد، لازم است تمام متدهای ویژهای که این کلاس از آنها پشتیبانی میکند، بازنویسی شوند؛ لطفاً برای اطلاع از متدهایی که در آن حالت باید فراهم شوند، به منابع مراجعه کنید.
UserString¶کلاس UserString بهعنوان پوششی برای اشیای رشته عمل میکند. نیاز به این کلاس تا حدی با امکان ایجاد زیرکلاس بهطور مستقیم از str جایگزین شده است؛ با این حال، کار با این کلاس میتواند آسانتر باشد، زیرا رشته زیرین بهعنوان یک ویژگی قابل دسترسی است.
کلاسی که یک شیء رشته را شبیهسازی میکند. محتوای نمونه در یک شیء رشته معمولی نگه داشته میشود، که از طریق ویژگی data نمونههای UserString قابل دسترسی است. محتوای نمونه در ابتدا روی یک کپی از seq تنظیم میشود. آرگومان seq میتواند هر شیءای باشد که بتوان آن را با استفاده از تابع توکار str() به رشته تبدیل کرد.
علاوه بر پشتیبانی از متدها و عملیات رشتهها، نمونههای UserString ویژگی زیر را فراهم میکنند:
یک شیء واقعی از نوع str که برای ذخیرهی محتوای کلاس UserString استفاده میشود.
تغییر یافته در نسخهی 3.5: متدهای جدید __getnewargs__، __rmod__، casefold، format_map، isprintable و maketrans.