collections --- انواع دادهی ظرف¶
کد منبع: Lib/collections/__init__.py
این ماژول انواع دادهی ظرف تخصصی را پیادهسازی میکند و جایگزینهایی برای ظرفهای توکار عمومی پایتون، dict، list، set و tuple فراهم میکند.
تابع کارخانهای (factory function) برای ایجاد زیرکلاسهای تاپل با فیلدهای نامدار |
|
ظرفی فهرستمانند با امکان افزودن و برداشتن سریع در هر دو انتها |
|
کلاس دیکشنریمانند برای ایجاد یک نمای واحد از چندین نگاشت |
|
زیرکلاس دیکشنری برای شمارش اشیاء hashable |
|
زیرکلاسی از dict که ترتیب افزوده شدن آیتمها را به خاطر میسپارد |
|
زیرکلاس dict که برای تأمین مقادیر گمشده، یک تابع کارخانه را فراخوانی میکند |
|
پوششی دور اشیای دیکشنری برای زیرکلاسسازی آسانتر از dict |
|
پوششی بر روی اشیای فهرست برای زیرکلاسسازی آسانتر فهرست |
|
پوششی بر روی اشیاء رشتهای برای زیرکلاسسازی آسانتر از رشته |
اشیاء ChainMap¶
اضافه شده در نسخهی 3.3.
کلاس ChainMap برای پیوند سریع تعدادی نگاشت فراهم شده است تا بتوان با آنها بهعنوان یک واحد رفتار کرد. این کار اغلب بسیار سریعتر از ایجاد یک دیکشنری جدید و اجرای چندین فراخوانی update() است.
این کلاس میتواند برای شبیهسازی محدودههای تودرتو استفاده شود و در قالببندی مفید است.
- class collections.ChainMap(*maps)¶
یک
ChainMapچندین دیکشنری یا نگاشتهای دیگر را در کنار هم قرار میدهد تا یک نمای واحد و بهروزرسانیپذیر ایجاد کند. اگر هیچ maps مشخص نشده باشد، یک دیکشنری خالی ارائه میشود تا یک زنجیره جدید همیشه حداقل یک نگاشت داشته باشد.نگاشتهای زیربنایی در یک فهرست ذخیره میشوند. آن فهرست عمومی است و میتوان با استفاده از ویژگی maps به آن دسترسی پیدا کرد یا آن را بهروزرسانی کرد. هیچ وضعیت دیگری وجود ندارد.
جستوجوها نگاشتهای زیرین را بهترتیب جستوجو میکنند تا کلیدی پیدا شود. در مقابل، نوشتنها، بهروزرسانیها و حذفها تنها روی اولین نگاشت عمل میکنند.
یک
ChainMapنگاشتهای زیربنایی را بهصورت ارجاعی در بر میگیرد. بنابراین، اگر یکی از نگاشتهای زیربنایی بهروزرسانی شود، آن تغییرات درChainMapمنعکس خواهند شد.تمام متدهای معمول دیکشنری پشتیبانی میشوند. علاوه بر این، یک ویژگی maps، یک متد برای ایجاد زیرزمینههای جدید، و یک پراپرتی برای دسترسی به همه نگاشتها بهجز اولین نگاشت وجود دارد:
- maps¶
فهرستی از نگاشتها که کاربر میتواند آن را بهروزرسانی کند. این فهرست به ترتیب از نخستین مورد جستجوشده تا آخرین مورد جستجوشده مرتب شده است. این تنها وضعیت ذخیرهشده است و میتوان آن را برای تغییر نگاشتهایی که جستجو میشوند، تغییر داد. این فهرست باید همواره شامل دستکم یک نگاشت باشد.
- new_child(m=None, **kwargs)¶
یک
ChainMapجدید برمیگرداند که شامل یک نگاشت جدید و به دنبال آن همهی نگاشتهای موجود در نمونه فعلی است. اگرmمشخص شده باشد، نگاشت جدید در ابتدای فهرست نگاشتها قرار میگیرد؛ اگر مشخص نشده باشد، از یک دیکشنری خالی استفاده میشود، بهطوری که فراخوانیd.new_child()معادلChainMap({}, *d.maps)است. اگر آرگومانهای کلیدواژهای مشخص شده باشند، آنها نگاشت دادهشده یا دیکشنری خالی جدید را بهروزرسانی میکنند. این متد برای ایجاد زیرزمینههایی استفاده میشود که میتوانند بدون تغییر مقادیر هیچیک از نگاشتهای والد بهروزرسانی شوند.تغییر یافته در نسخهی 3.4: پارامتر اختیاری
mاضافه شد.تغییر یافته در نسخهی 3.10: پشتیبانی از آرگومانهای کلیدواژهای افزوده شد.
- parents¶
ویژگیای که یک
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)]
- class collections.Counter(**kwargs)¶
- class collections.Counter(iterable, /, **kwargs)
- class collections.Counter(mapping, /, **kwargs)
یک
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()¶
یک پیمایشگر بر روی عناصر برمیگرداند که هر عنصر را به تعداد آن تکرار میکند. عناصر به ترتیبی که برای اولین بار مشاهده شدهاند برگردانده میشوند. اگر تعداد یک عنصر کمتر از ۱ باشد،
elements()آن را نادیده میگیرد.>>> c = Counter(a=4, b=2, c=0, d=-2) >>> sorted(c.elements()) ['a', 'a', 'a', 'a', 'b', 'b']
- most_common(n=None)¶
فهرستی از رایجترین n عنصر و تعداد آنها را از رایجترین به کمترین برمیگرداند. اگر n حذف شود یا
Noneباشد،most_common()تمام عناصر موجود در شمارنده را برمیگرداند. عناصری که تعداد برابر دارند، به ترتیبی که برای اولین بار مشاهده شدهاند مرتب میشوند:>>> Counter('abracadabra').most_common(3) [('a', 5), ('b', 2), ('r', 2)]
- subtract(**kwargs)¶
- subtract(iterable, /, **kwargs)
- subtract(mapping, /, **kwargs)
عناصر از یک پیمایشپذیر یا از یک نگاشت دیگر (یا شمارنده) کم میشوند. مانند
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.
- total()¶
مجموع شمارشها را محاسبه کنید.
>>> c = Counter(a=10, b=5, c=0) >>> c.total() 15
اضافه شده در نسخهی 3.10.
متدهای معمول دیکشنری برای اشیای
Counterدر دسترس هستند، بهجز دو مورد که برای شمارندهها متفاوت عمل میکنند.- update(**kwargs)¶
- update(iterable, /, **kwargs)
- update(mapping, /, **kwargs)
المانها از یک پیمایشپذیر شمرده میشوند یا از یک نگاشت (یا شمارنده) دیگر افزوده میشوند. مانند
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 # 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: پشتیبانی از عملگرهای یکعملوندی مثبت و منفی و عملیاتهای چندمجموعهای درجا افزوده شد.
توجه
شمارندهها عمدتاً برای کار با اعداد صحیح مثبت به منظور نمایش شمارشهای جاری طراحی شدهاند؛ با این حال، دقت شده است که بهطور غیرضروری از موارد استفادهای که نیازمند انواع دیگر یا مقادیر منفی هستند جلوگیری نشود. برای کمک به این موارد استفاده، این بخش حداقل دامنه و محدودیتهای نوع را مستند میکند.
خود کلاس
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¶
- class collections.deque([iterable[, maxlen]])¶
یک شیء 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 از متدهای زیر پشتیبانی میکنند:
- append(item, /)¶
item را به سمت راست deque میافزاید.
- appendleft(item, /)¶
item را به سمت چپ deque اضافه کنید.
- clear()¶
همهی عناصر را از صف دوطرفه (deque) حذف میکند و طول آن را به ۰ میرساند.
- copy()¶
یک کپی سطحی از deque ایجاد میکند.
اضافه شده در نسخهی 3.5.
- count(value, /)¶
تعداد عناصر deque برابر با value را میشمارد.
اضافه شده در نسخهی 3.2.
- extend(iterable, /)¶
سمت راست deque را با افزودن المانها از آرگومان پیمایشپذیر گسترش دهید.
- extendleft(iterable, /)¶
سمت چپ صف دوطرفه (deque) را با الحاق عناصری از iterable گسترش دهید. توجه داشته باشید که دنبالهی الحاقهای سمت چپ، باعث معکوس شدن ترتیب عناصر در آرگومان پیمایشپذیر میشود.
- index(value[, start[, stop]])¶
موقعیت value را در صف دوطرفه (deque) برمیگرداند (در اندیس start یا پس از آن و پیش از اندیس stop). نخستین تطابق را برمیگرداند یا در صورت پیدا نشدن،
ValueErrorرا پرتاب میکند.اضافه شده در نسخهی 3.5.
- insert(index, value, /)¶
value را در موقعیت index در صف دوطرفه (deque) درج کنید.
اگر درج موجب شود که یک deque کراندار بزرگتر از maxlen شود، یک
IndexErrorپرتاب میشود.اضافه شده در نسخهی 3.5.
- pop()¶
یک المان را از سمت راست deque حذف کرده و برمیگرداند. اگر هیچ المانی وجود نداشته باشد، یک
IndexErrorپرتاب میشود.
- popleft()¶
یک عنصر را از سمت چپ deque حذف میکند و آن را برمیگرداند. اگر هیچ عنصری وجود نداشته باشد، یک
IndexErrorپرتاب میشود.
- remove(value, /)¶
اولین رخداد value را حذف میکند. اگر پیدا نشد، یک
ValueErrorپرتاب میکند.
- reverse()¶
عناصر deque را بهصورت درجا معکوس میکند و سپس
Noneرا برمیگرداند.اضافه شده در نسخهی 3.2.
- rotate(n=1, /)¶
deque را n گام به راست بچرخانید. اگر n منفی باشد، به چپ بچرخانید.
هنگامی که deque خالی نیست، چرخاندن یک گام به راست معادل
d.appendleft(d.pop())است، و چرخاندن یک گام به چپ معادلd.append(d.popleft())است.
اشیای Deque همچنین یک ویژگی فقطخواندنی ارائه میدهند:
- maxlen¶
حداکثر اندازهی یک 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
A round-robin scheduler can be implemented with
input iterators stored in a deque. Values are yielded from the active
iterator in position zero. If that iterator is exhausted, it can be removed
with popleft(); otherwise, it can be cycled back to the end with
the rotate() method:
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¶
- class collections.defaultdict(default_factory=None, /, **kwargs)¶
- class collections.defaultdict(default_factory, mapping, /, **kwargs)
- class collections.defaultdict(default_factory, iterable, /, **kwargs)
یک شیء دیکشنریمانند جدید برمیگرداند.
defaultdictزیرکلاسی از کلاس توکارdictاست. این کلاس یک متد را بازتعریف میکند و یک متغیر نمونه قابلنوشتن اضافه میکند. سایر قابلیتها مانند کلاسdictهستند و در اینجا مستند نشدهاند.نخستین آرگومان مقدار اولیهی ویژگی
default_factoryرا فراهم میکند؛ مقدار پیشفرض آنNoneاست. با تمام آرگومانهای باقیمانده همانگونه رفتار میشود که گویی به سازندهیdictارسال شده باشند، از جمله آرگومانهای کلیدواژهای.defaultdictها نسبت به دو نوع عام هستند که (بهترتیب) بیانگر انواع کلیدها و مقادیر دیکشنری هستند.اشیای
defaultdictعلاوه بر عملیات استانداردdict، از متد زیر نیز پشتیبانی میکنند:- __missing__(key, /)¶
اگر ویژگی
default_factoryبرابرNoneباشد، این عمل یک استثنایKeyErrorرا با key بهعنوان آرگومان پرتاب میکند.اگر
default_factoryبرابرNoneنباشد، بدون آرگومان فراخوانی میشود تا مقدار پیشفرضی برای کلید دادهشده فراهم کند؛ این مقدار در دیکشنری برای کلید درج میشود و برگردانده میشود.اگر فراخوانی
default_factoryباعث پرتاب استثنایی شود، این استثنا بدون تغییر انتشار مییابد.این متد توسط متد
__getitem__()از کلاسdictزمانی فراخوانی میشود که کلید درخواستشده یافت نشود؛ هر آنچه برگرداند یا پرتاب کند، سپس توسط__getitem__()برگردانده یا پرتاب میشود.توجه داشته باشید که
__missing__()برای هیچ عملیاتی به جز__getitem__()فراخوانی نمیشود. این بدان معناست کهget()مانند دیکشنریهای معمولی، به جای استفاده ازdefault_factory،Noneرا بهعنوان مقدار پیشفرض برمیگرداند.
اشیای
defaultdictاز متغیر نمونهی زیر پشتیبانی میکنند:- default_factory¶
این ویژگی توسط متد
__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() تابع کارخانه برای تاپلهای دارای فیلدهای نامدار¶
تاپلهای نامدار به هر جایگاه در یک تاپل معنا میبخشند و امکان کدی خواناتر و خودمستند را فراهم میکنند. این تاپلها میتوانند هر جا که تاپلهای معمولی استفاده میشوند، به کار روند و توانایی دسترسی به فیلدها از طریق نام بهجای اندیس جایگاه را اضافه کنند.
- collections.namedtuple(typename, field_names, *, rename=False, defaults=None, module=None)¶
یک زیرکلاس جدید از تاپل به نام 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)
علاوه بر متدهای به ارث بردهشده از تاپلها، تاپلهای نامدار از سه متد و دو ویژگی اضافی پشتیبانی میکنند. برای جلوگیری از تداخل با نام فیلدها، نام متدها و ویژگیها با یک زیرخط شروع میشوند.
- classmethod somenamedtuple._make(iterable, /)¶
متد کلاسی که یک نمونه جدید را از یک دنباله یا پیمایشپذیر موجود میسازد.
>>> t = [11, 22] >>> Point._make(t) Point(x=11, y=22)
- somenamedtuple._asdict()¶
یک
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()).
- somenamedtuple._replace(**kwargs)¶
یک نمونه جدید از تاپل نامدار (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ایجاد میکند.
- somenamedtuple._fields¶
تاپلی از رشتهها که نام فیلدها را فهرست میکند. برای دروننگری و ایجاد انواع جدیدی از تاپلهای نامدار از تاپلهای نامدار موجود مفید است.
>>> 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)
- somenamedtuple._field_defaults¶
دیکشنریای که نام فیلدها را به مقادیر پیشفرض نگاشت میکند.
>>> 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__()بود.
- class collections.OrderedDict(**kwargs)¶
- class collections.OrderedDict(mapping, /, **kwargs)
- class collections.OrderedDict(iterable, /, **kwargs)
نمونهای از یک زیرکلاس
dictبرمیگرداند که دارای متدهایی اختصاصی برای بازآرایی ترتیب دیکشنری است.اضافه شده در نسخهی 3.1.
- popitem(last=True)¶
متد
popitem()برای دیکشنریهای ترتیبدار یک جفت (کلید، مقدار) را برمیگرداند و حذف میکند. اگر last درست باشد، جفتها به ترتیب LIFO و اگر نادرست باشد، به ترتیب FIFO برگردانده میشوند.
- move_to_end(key, last=True)¶
یک 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 the keys were last added'
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 جایگزین شده است؛ با این حال، کار با این کلاس میتواند آسانتر باشد، زیرا دیکشنری زیرین بهعنوان یک ویژگی قابل دسترسی است.
- class collections.UserDict(**kwargs)¶
- class collections.UserDict(mapping, /, **kwargs)
- class collections.UserDict(iterable, /, **kwargs)
کلاسی که یک دیکشنری را شبیهسازی میکند. محتویات نمونه در یک دیکشنری معمولی نگهداری میشود، که از طریق ویژگی
dataنمونههایUserDictقابل دسترسی است. اگر آرگومانهایی ارائه شوند، از آنها برای مقداردهی اولیهیdataاستفاده میشود، مانند یک دیکشنری معمولی.علاوه بر پشتیبانی از متدها و عملیات نگاشتها، نمونههای
UserDictویژگی زیر را فراهم میکنند:
اشیاء UserList¶
این کلاس بهعنوان پوششی برای اشیای فهرست عمل میکند. این کلاس، کلاس پایه مفیدی برای کلاسهای فهرستمانند خودتان است که میتوانند از آنها ارثبری کنند، متدهای موجود را بازنویسی کنند یا متدهای جدیدی اضافه کنند. به این ترتیب، میتوان رفتارهای جدیدی به فهرستها اضافه کرد.
نیاز به این کلاس تا حدی با امکان زیرکلاسگیری مستقیم از list جایگزین شده است؛ با این حال، کار با این کلاس میتواند آسانتر باشد، زیرا فهرست زیربنایی بهعنوان یک ویژگی قابل دسترسی است.
- class collections.UserList([list])¶
کلاسی که یک فهرست را شبیهسازی میکند. محتوای نمونه در یک فهرست معمولی نگهداری میشود، که از طریق ویژگی
dataدر نمونههایUserListقابل دسترسی است. محتوای نمونه در ابتدا به یک کپی از list تنظیم میشود، که بهطور پیشفرض فهرست خالی[]است. list میتواند هر پیمایشپذیری باشد، برای مثال یک فهرست واقعی پایتون یا یک شیءUserList.علاوه بر پشتیبانی از متدها و عملیات دنبالههای تغییرپذیر، نمونههای
UserListویژگی زیر را ارائه میدهند:
الزامات زیرکلاسسازی: انتظار میرود زیرکلاسهای UserList سازندهای ارائه دهند که بتوان آن را بدون آرگومان یا با یک آرگومان فراخوانی کرد. عملیات فهرستی که دنبالهی جدیدی بازمیگردانند، تلاش میکنند نمونهای از کلاس پیادهسازی واقعی ایجاد کنند. برای این کار، فرض میشود که سازنده میتواند با یک پارامتر فراخوانی شود، که یک شیء دنباله است و بهعنوان منبع داده استفاده میشود.
اگر یک کلاس مشتق مایل به رعایت این الزام نباشد، لازم است تمام متدهای ویژهای که این کلاس از آنها پشتیبانی میکند، بازنویسی شوند؛ لطفاً برای اطلاع از متدهایی که در آن حالت باید فراهم شوند، به منابع مراجعه کنید.
اشیاء UserString¶
کلاس UserString بهعنوان پوششی برای اشیای رشته عمل میکند. نیاز به این کلاس تا حدی با امکان ایجاد زیرکلاس بهطور مستقیم از str جایگزین شده است؛ با این حال، کار با این کلاس میتواند آسانتر باشد، زیرا رشته زیرین بهعنوان یک ویژگی قابل دسترسی است.
- class collections.UserString(seq)¶
کلاسی که یک شیء رشته را شبیهسازی میکند. محتوای نمونه در یک شیء رشته معمولی نگه داشته میشود، که از طریق ویژگی
dataنمونههایUserStringقابل دسترسی است. محتوای نمونه در ابتدا روی یک کپی از seq تنظیم میشود. آرگومان seq میتواند هر شیءای باشد که بتوان آن را با استفاده از تابع توکارstr()به رشته تبدیل کرد.علاوه بر پشتیبانی از متدها و عملیات رشتهها، نمونههای
UserStringویژگی زیر را فراهم میکنند:- data¶
یک شیء واقعی از نوع
strکه برای ذخیرهی محتوای کلاسUserStringاستفاده میشود.
تغییر یافته در نسخهی 3.5: متدهای جدید
__getnewargs__،__rmod__،casefold،format_map،isprintableوmaketrans.