Collections در پایتون

462
Collections در پایتون

ماژول Collections که یکی از ماژول‌های درون‌هسته‌ی زبان برنامه‌نویسی پایتون است، انواع مختلف و کارآمدی از کانتینرها را به ما ارائه می‌دهد. کانتینر یک شیء است که برای ذخیره‌سازی اشیاء مختلف استفاده می‌شود و راهی برای دسترسی به اشیاء موجود و پیمایش روی آن‌ها فراهم می‌کند. به‌طور کلی در برنامه‌ها ما از List ،Tuple ،Dictionary و Set که نوع‌داده‌ها و کانتینرهای پیش‌فرض پایتون هستند استفاده می‌کنیم. اما وقتی که با داده‌های پیچیده‌تر و ساخت‌یافته سروکار داریم، نیاز به کانتینرهای هوشمندتری نیز داریم.

در این مقاله با هم نگاهی به برخی از این ساختمان‌داده‌ها خواهیم داشت و با کاربرد هر یک آشنا خواهیم شد.

namedtuple

می‌توانیم namedtuple را یک نسخه‌ی بهبودیافته از tuple در نظر بگیریم که به ما امکان ایجاد یک کلاس‌ با فیلدهای مشخص را می‌دهد. کلیدی‌ترین تفاوت بین namedtuple و tuple، نحوه‌ی دسترسی به داده‌هاست. در tuple ما تنها از طریق ایندکس‌ها می‌توانیم به عنصر مورد‌نظر دسترسی پیدا کنیم. در صورتی که در namedtuple علاوه بر ایندکس، از طریق نام هر فیلد نیز می‌توانیم به مقدار آن دسترسی پیدا کنیم.

برای ایجاد یک namedtuple و شیءهایی از آن می‌توانیم به شکل زیر عمل کنیم:

>>> from collections import namedtuple
>>> movie = namedtuple('movie', ['genre', 'rating', 'lead_actor'])
>>> ironman = movie(genre='action', rating=8.5, lead_actor='robert downey junior')
>>> ironman.rating
8.5
>>> ironman[1]
8.5

در کد بالا، ابتدا از ماژول Collections، کلاس namedtuple را وارد کردیم و در خط دوم، یک namedtuple ساختیم که یک فیلم را با فیلدهای ژانر، امتیاز و هنرپیشه‌ی اصلی تعریف می‌کند. به‌طور کلی برای ایجاد یک namedtuple نیاز به مشخص کردن یک نام (typename) و شناسه‌ی فیلدها داریم. فیلدها می‌توانند در قالب لیستی از رشته‌ها یا رشته‌ای ساده که با space فیلدها را از یکدیگر جدا کرده است، بیایند. همانطور که در کد بالا مشاهده می‌کنید، ما با استفاده از شناسه‌ی هر فیلد می‌توانیم به مقدار آن دسترسی داشته باشیم و این سهولت دسترسی به داده باعث شده تا کدی خواناتر بنویسیم. از دیگر مزیت‌های مهم namedtuple می‌توان به مصرف کمتر حافظه نسبت به دیکشنری معادل اشاره کرد؛ بنابراین هنگام کار با حجم زیادی از داده‌ها استفاده از namedtupleها باعث بهینگی خواهد شد.

namedtuple همچنین دارای متدهای متنوعی هست که می‌توانید از آن‌ها استفاده کنید. در اینجا دو مورد از این متدها را باهم بررسی خواهیم کرد:

  • ()asdict_
    این متد به شما اجازه می‌دهد تا شیء namedtuple خود را به یک دیکشنری تبدیل کنید.
>>> ironman._asdict()
{'genre': 'action', 'rating': 8.5, 'lead_actor': 'robert downey junior'}
  • (kwargs**)replace_
    این متد، یک شیء جدید از namedtuple که مقدار فیلدهای آن با kwargs جایگزین شده‌اند را برمی‌گرداند.
>>> ironman = ironman._replace(rating=8)
>>> ironman.rating
8

Counter

این کتابخانه از ماژول Collections پایتون که خود زیرکلاسی از کلاس نوع‌داده‌ی dict است، به ما این امکان را می‌دهد تا خیلی راحت بتوانیم تعداد تکرار عناصر در اشیای hashable را محاسبه کنیم. شیء Counter یک دیکشنری برمی‌گرداند که عناصر ما به‌عنوان کلیدهای دیکشنری و تعداد تکرارشان به‌عنوان مقدار آن کلید قرار گرفته‌اند.

>>> from collections import Counter
>>> Counter("abracadabra")
Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})

همان طور که اشاره کردیم، Counter از کلاس dict به ارث رسیده است ولی یکی از تفاوت‌های کلیدی Counter با دیکشنری، رفتار آن‌ها در مواجه‌شدن با کلیدی است که در دیکشنری موجود نباشد. در دیکشنری اکسپشن KeyError پرتاب می‌شود ولی در Counter مقدار 0 برمی‌گردد.

بنابر خاصیت ارث‌بری، کلاس Counter، تمامی متدهای کلاس dict را شامل می‌شود. اما علاوه بر این متدها، چهار متد اضافه‌‌تر نیز دارد که در این مقاله به بررسی آن‌ها می‌پردازیم.

  • ()elements
    این متد یک iterator شامل تمامی عنصرها که هرکدام به اندازه‌ی تعدادشان تکرار شده‌اند را بر می‌گرداند. لازم به ذکر است که اگر تعداد یک عنصر کمتر از یک باشد، این متد آن را نادیده می‌گیرد.
>>> c = Counter(a=4, b=2, c=0, d=-2)
>>> sorted(c.elements())
['a', 'a', 'a', 'a', 'b', 'b']
  • ([n])most_common
    این متد لیستی از n پرتکرارترین عناصر شیء ما را به همراه تعداد تکرارشان به ترتیب غیر‌صعودی برمی‌گرداند. در صورتی که عدد n مشخص نشده باشد، این تابع تمامی عناصر موجود در شیء Counter را برمی‌گرداند.
>>> Counter('abracadabra').most_common(3)
[('a', 5), ('b', 2), ('r', 2)]
  • ([iterable-or-mapping])subtract
    این متد که در پایتون 3.2 معرفی شد، در آرگومان خود یک شیء iterable یا یک شیء mapping می‌گیرد و تعداد تکرار عنصرها را از آرگومان داده‌شده کسر می‌کند.
>>> 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})
  • ()total
    این متد که در پایتون 3.10 معرفی شد، مجموع تعداد تکرارها را برمی‌گرداند.
>>> c = Counter(a=10, b=5, c=0)
>>> c.total()
15

deque

deque که کوتهاه‌شده‌ی double-ended queue است، برای ما لیستی را فراهم می‌کند تا بتوانیم با پیچیدگی زمانی O(1) و مصرف حافظه‌ی بهینه، عملیات pop و append را از هر دو سمت لیست داشته باشیم. این ساختمان‌داده اولین کتابخانه‌ای بود که به ماژول Collections در زمان انتشار پایتون 2.4 اضافه شد و هدف اصلی آن حل مشکلات کارایی در عملیات pop و append لیست درون‌هسته‌ی پایتون بود. با حل این مشکلات، این نوع‌داده به یکی از بهترین گزینه‌ها برای پیاده‌سازی استک و صف دلخواه در پایتون تبدیل شد.

برای ایجاد یک شیء deque می‌توانیم به شکل زیر عمل کنیم:

>>> from collections import deque
>>> queue = deque(['Quera', 'Python', 'Blog'])
deque(['Quera', 'Python', 'Blog'])

جهت اضافه کردن یک عنصر به deque، می‌توانیم از توابع append و appendleft استفاده کنیم که به‌ترتیب یک عنصر را به سمت راست لیست و یک عنصر را به سمت چپ لیست اضافه می‌کند.

>>> queue.append(18)
>>> queue.appendleft(24)
>>> queue
deque([24, 'Quera', 'Python', 'Blog', 18])

و برای حذف کردن یک عنصر از deque، می‌توانیم از تابع‌های pop و popleft استفاده کنیم که به‌ترتیب یک عنصر را از سمت راست لیست و یک عنصر را از سمت چپ لیست حذف می‌کند.

>>> queue.pop()
18
>>> queue
deque([24, 'Quera', 'Python', 'Blog'])
>>> queue.popleft()
24
>>> queue
deque(['Quera', 'Python', 'Blog'])

همچنین برای شمارش تعداد تکرار یک عنصر داخل لیست از تابع count و برای حذف تمامی عناصر لیست از تابع clear می‌توانیم استفاده کنیم. لازم به ذکر است deque متدهای کاربردی فراوانی دارد که در این لینک می‌توانید آن‌ها را مطالعه بفرمایید.

defaultdict

استفاده از ساختمان داده دیکشنری برای ذخیره‌سازی داده‌ها یکی از رایج‌ترین انتخاب‌‌های هر برنامه‌‌نویس است. کتابخانه‌ی defaultdict که یکی دیگر از ساختمان‌داده‌هایی است که توسط ماژول Collections فراهم شده است، با ارث‌بری از کلاس درون‌هسته‌ی dict پایتون و override کردن یک متد آن (__missing__)، برای کلیدهایی که در دیکشنری وجود ندارد یک مقدار پیش‌فرض در نظر می‌گیرد و هیچ‌گاه اکسپشن KeyError را پرتاب نمی‌کند.

برای ساخت یک شیء DefaultDict به شکل زیر عمل می‌کنیم:

>>> from collections import defaultdict
>>> m = defaultdict(list)
>>> m["Quera"]
[]

آرگومانی که به تابع سازنده‌ی این شیء پاس داده می‌شود، default_factory هست که مقدار پیش‌فرض ما را ایجاد می‌کند. هنگامی که یک کلید را که در دیکشنری موجود نیست فراخوانی می‌کنیم، متد __missing__ صدا زده می‌شود. در این متد ابتدا مقدار default_factory چک می‌شود که آیا برابر None هست یا خیر. اگر برابر None بود، اکسپشن KeyError رخ می‌دهد. در غیر این صورت، default_factory بدون آرگومان فراخوانی می‌شود تا مقدار پیش‌فرض را تهیه کند.

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

کیان مجلسی

ممکن است علاقه‌مند باشید
اسکیل‌آپِ Back-End (تابستان ۱۴۰۱)
تابستون چلنج؛ ۷ روز، ۷ چالش
مدیریت یک پروژه بزرگ در گیت
اشتراک در
اطلاع از
guest
0 دیدگاه‌
بازخورد (Feedback) های اینلاین
View all comments