ویژگی تصویر

آشنایی با کتابخانه collections در پایتون

  /  پایتون   /  کتابخانه collections در پایتون
بنر تبلیغاتی الف

ماژول collections یکی از ابزارهای پایه‌ای و پرکاربرد در پایتون است که ساختمان داده‌های پیشرفته‌تر و بهینه‌تری را نسبت به لیست و دیکشنری ساده در اختیار توسعه‌دهنده قرار می‌دهد. این مقاله به معرفی کلاس‌های اصلی این ماژول، مثال‌های واقعی، نکات عملکردی و بهترین کاربردها می‌پردازد.

چرا از collections استفاده کنیم؟

هدف اصلی این ماژول ارائه‌ی ساختارهایی است که برای مسائلی مانند شمارش، صف و پشته، نگهداری ترتیب درج، نگاشت چندگانه و نام‌گذاری فیلدها مناسب‌تر و سریع‌تر هستند. استفاده درست از این کلاس‌ها می‌تواند خوانایی کد و کارایی را به‌طرز محسوسی افزایش دهد.

مقدمه‌ای بر کلاس‌های مهم

  • Counter: شمارش فرکانس عناصر
  • defaultdict: دیکشنری با مقدار پیش‌فرض
  • deque: صف/پشته دوطرفه با عملیات O(1) در ابتدا و انتها
  • namedtuple: تاپل نام‌دار با فیلدهای قابل دسترسی به‌صورت صفت
  • OrderedDict: دیکشنری با حفظ ترتیب درج (در پایتون جدید dict این رفتار را دارد اما OrderedDict متدهای اضافی دارد)
  • ChainMap: ترکیب چند دیکشنری برای جستجو پشت‌سرهم

Counter — شمارش کارآمد

from collections import Counter

data = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']
c = Counter(data)
print(c.most_common(2))  # [('apple', 3), ('banana', 2)]

در این مثال، Counter فرکانس هر عنصر را محاسبه و متد most_common دو عنصر پرتکرار را برمی‌گرداند. Counter برای تحلیل لاگ‌ها، شمارش کلمات و تجزیه‌ی داده‌های آماری ایده‌آل است.

defaultdict — جلوگیری از خطای KeyError

from collections import defaultdict

d = defaultdict(int)
words = ["cat","dog","cat"]
for w in words:
    d[w] += 1
print(dict(d))  # {'cat': 2, 'dog': 1}

در این کد، اگر کلیدی وجود نداشته باشد، مقدار پیش‌فرض صفر (از نوع int) ایجاد می‌شود. این روش معمولاً خواناتر و امن‌تر از استفاده از شرط‌ها یا try/except است.

deque — صف و پشته سریع

from collections import deque

q = deque()
q.append('a')
q.append('b')
q.appendleft('z')
print(q)        # deque(['z', 'a', 'b'])
q.pop()
print(q)        # deque(['z', 'a'])
q.popleft()
print(q)        # deque(['a'])

deque برای پیاده‌سازی صف (FIFO) و پشته (LIFO) مناسب است؛ زیرا عملیات افزودن/حذف از ابتدا یا انتها با پیچیدگی زمانی O(1) انجام می‌شود. از لیست برای pop(0) یا insert(0, x) استفاده نکنید چون هزینه‌بر است.

namedtuple — خوانایی و سبک‌تر از کلاس

from collections import namedtuple

Point = namedtuple('Point', ['x', 'y'])
p = Point(10, 20)
print(p.x, p.y)  # 10 20

namedtuple ترکیبی از تاپل و کلاس سبک است: مقادیر ایمن، قابل‌خواندن و حافظه-بهره‌ور. اگر به قابلیت تغییر (mutable) نیاز دارید، از dataclass یا کلاس استفاده کنید؛ namedtuple مقادیر را غیرقابل‌تغییر نگه می‌دارد.

OrderedDict — ترتیب و متدهای کمکی

from collections import OrderedDict

od = OrderedDict()
od['a'] = 1
od['b'] = 2
od['c'] = 3
od.move_to_end('b')
print(list(od.keys()))  # ['a', 'c', 'b']

در نسخه‌های جدید پایتون استاندارد dict نیز ترتیب درج را حفظ می‌کند، اما OrderedDict متدهایی مانند move_to_end و popitem(last=False) را ارائه می‌دهد که برای الگوریتم‌هایی که نیاز به جابجایی ترتیب دارند مفید است (مثلاً الگوریتم LRU cache ساده).

ChainMap — ترکیب چند نگاشت

from collections import ChainMap

defaults = {'theme': 'light', 'lang': 'en'}
user = {'lang': 'fa'}
cfg = ChainMap(user, defaults)
print(cfg['theme'], cfg['lang'])  # light fa

ChainMap امکان ترکیب چند دیکشنری را بدون کپی‌برداری فراهم می‌کند؛ مفید در مدیریت تنظیمات (defaults و user overrides) یا اسکوپ‌های مختلف برنامه‌نویسی.

مقایسه عملکرد و نکات حرفه‌ای

کلاسکاربردمزیت کلیدی
Counterشمارش فرکانسمتدهای آماده مثل most_common
defaultdictدیکشنری با مقدار پیش‌فرضکاهش خطا و شرط‌ها
dequeصف/پشتهعملیات O(1) در ابتدا/انتها
namedtupleساختار داده سبکخوانایی و ثابت بودن
OrderedDictدیکشنری مرتبمتدهای ترتیب‌دهی اضافی

نمونه‌های واقعی و الگوهای کاربردی

  • آنالیز متن: استفاده از Counter برای شمارش کلمات پرتکرار.
  • پیاده‌سازی صف پیام: استفاده از deque برای مصرف‌کننده و تولیدکننده.
  • تنظیمات برنامه: ChainMap برای ترکیب تنظیمات پیش‌فرض و کاربر.
  • کش LRU ساده: OrderedDict با popitem و move_to_end.

مثال: پیاده‌سازی LRU cache ساده با OrderedDict

from collections import OrderedDict

class LRUCache:
    def __init__(self, capacity=3):
        self.cache = OrderedDict()
        self.capacity = capacity

    def get(self, key):
        if key not in self.cache:
            return -1
        value = self.cache.pop(key)
        self.cache[key] = value  # move to end (most recently used)
        return value

    def put(self, key, value):
        if key in self.cache:
            self.cache.pop(key)
        elif len(self.cache) >= self.capacity:
            self.cache.popitem(last=False)  # remove least recently used
        self.cache[key] = value

این کلاس از OrderedDict برای نگهداری ترتیب دسترسی استفاده می‌کند. متد get آیتم را به انتها منتقل می‌کند و متد put در صورت پر بودن کش، آیتم قدیمی‌ترین را حذف می‌کند. این الگو ساده و کارا برای آموزش LRU است؛ در پروژه‌های واقعی از functools.lru_cache یا پیاده‌سازی‌های بهینه‌تر استفاده کنید.

نکات بهینه‌سازی و هشدارها

  • در پایتون 3.7+، dict مرتب است؛ استفاده از OrderedDict تنها زمانی لازم است که به متدهای خاص آن نیاز داشته باشید.
  • Counter مناسب عملیات تک‌تردی و سریع شمارش است؛ برای شمارش در داده‌های بسیار بزرگ از itertools یا پردازش دسته‌ای استفاده کنید.
  • deque برای کارآمدی حافظه و زمان در صف‌ها و اتصال‌های دوطرفه برتر از لیست است.
  • namedtuple حافظه کمتر و سرعت بالاتر نسبت به کلاس معمولی دارد، اما غیرقابل‌تغییر است؛ اگر نیاز به قابلیت تغییر دارید، dataclass گزینه بهتری است.

جمع‌بندی

ماژول collections مجموعه‌ای از ساختارهای داده‌ای کارا و خوانا را ارائه می‌دهد که در اکثر پروژه‌های عملی کاربرد دارند. آشنایی با این کلاس‌ها و انتخاب درست آن‌ها می‌تواند موجب ساده‌تر شدن پیاده‌سازی‌ها و بهبود کارایی شود. توصیه می‌شود هنگام مواجهه با مسائلی مانند شمارش، صف/پشته، نگهداری ترتیب یا ترکیب تنظیمات، ابتدا بررسی کنید آیا یکی از ابزارهای collections پاسخ مناسب را ارائه می‌دهد یا خیر.

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: