آموزش

دیکشنری کامپرهنشن در پایتون: نکات ضروری که باید بدونی

همه چیز رو درباره دیکشنری کامپرهنشن در پایتون یاد می‌گیری. یاد می‌گیری چطور می‌تونی از اون برای ساخت دیکشنری‌ها استفاده کنی، تا حلقه‌های for تودرتو یا توابع لامبدا رو با ()map و ()filter و ()reduce و موارد دیگه جایگزین کنی.

تاریخ انتشار:
10 شهریور 1405
پایتون
14 دقیقه
سواد داده‌ای
داده‌های بزرگ
کاربرهای فینکا در چه شرکت‌هایی مشغول به کار هستند؟

دیکشنری‌ها مثل لیست‌های پایتون روشی برای ذخیره کردن داده‌ها هستن. با این تفاوت که به جای استفاده از اندیس برای دسترسی به عناصر، به هر عنصر یه کلید (key) ثابت اختصاص می‌دی و با همون کلید بهش دسترسی پیدا می‌کنی. اینجا با یه جفت «کلید-مقدار» (key-value) سروکار داری که برای خیلی از مسائل، ساختار داده‌ی مناسب‌تری نسبت به یه لیست ساده‌ست. موقع کار در زمینه‌ی علم داده، خیلی وقت‌ها باید با دیکشنری‌ها کار کنی، پس بهتره به دیکشنری کامپرهنشن مسلط بشی.

در این آموزش:

  • اول می‌بینی که دیکشنری پایتون دقیقاً چیه و چطور می‌تونی خیلی خوب ازش استفاده کنی.
  • بعد با دیکشنری کامپرهنشن در پایتون آشنا می‌شی؛ می‌فهمی چیه، چرا مهمه و چطوری می‌تونه جایگزین حلقه‌های for و توابع لامبدا بشه.
  • یاد می‌گیری که چطوری به دیکشنری کامپرهنشن شرط اضافه کنی؛ یعنی با شرط‌های if، شرط‌های چندگانه if و همین‌طور دستورات if-else کار کنی.
  • در نهایت هم یاد می‌گیری دیکشنری کامپرهنشن تو در تو چیه، چطور ازش استفاده کنی و چطور می‌تونی در صورت نیاز اون رو با حلقه‌های for بازنویسی کنی.

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

دیکشنری پایتون چیه؟

دیکشنری در پایتون مجموعه‌ای از عناصره که دسترسی به اون‌ها از طریق یه کلید خاص انجام می‌شه، نه اندیس. اما این یعنی چی؟

یه فرهنگ لغت واقعی رو تصور کن. وقتی می‌خوای معنی یه کلمه رو پیدا کنی، از خود کلمه استفاده می‌کنی، نه اینکه دنبال شماره‌ی اون کلمه در کتاب بگردی. دیکشنری‌های پایتون هم دقیقاً همین‌طوری کار می‌کنن: کلمه‌ای که دنبالشی همون کلیده و معنیش می‌شه مقدار اون کلید. برای پیدا کردن مقدارش هم اصلاً نیازی نیست اندیسش رو بدونی.

ساخت دیکشنری در پایتون

در پایتون می‌تونی یه دیکشنری رو به این شکل بسازی:

خروجی
fruit
خروجی
Traceback (most recent call last):
  File "C:\Users\YourName\Desktop\test.py", line 1, in <module>
    print(a[0])
KeyError: 0

اول، یه دیکشنری به اسم a می‌سازیم که سه جفت کلید-مقدار داره: 'apple': 'fruit'، 'beetroot': 'vegetable' و 'cake': 'dessert'. کلیدها رشته‌هایی هستن که اسم آیتم‌ها رو نشون می‌دن و مقادیر هم رشته‌هایی هستن که نوع یا دسته‌بندی اون آیتم رو مشخص می‌کنن.

بعد، با استفاده از سینتکس a['doughnut'] = 'snack' یه جفت کلید-مقدار جدید رو به دیکشنری a اضافه می‌کنیم. با این کار، کلید 'doughnut' با مقدار 'snack' وارد دیکشنری می‌شه.

خط سوم کد، مقدار مربوط به کلید 'apple' در دیکشنری a رو چاپ می‌کنه. چون 'apple' به عنوان یه کلید در دیکشنری وجود داره، خروجی 'fruit' چاپ می‌شه.

خط چهارم سعی می‌کنه مقدار مربوط به کلید 0 رو چاپ کنه، ولی این کلید در دیکشنری ما تعریف نشده. به همین خاطر، یه خطای KeyError می‌گیریم که نشون می‌ده داریم تلاش می‌کنیم به کلیدی دسترسی پیدا کنیم که وجود نداره.

انواع داده‌ها در دیکشنری پایتون

عناصر یه دیکشنری می‌تونن از هر نوع داده‌ای باشن. برای اینکه بهتر متوجه بشی، بیا چند تا مثال دیگه از دیکشنری رو با هم ببینیم:

یه دیکشنری به اسم a با چهار جفت کلید-مقدار بساز:

مقدار مربوط به کلید 'one' در دیکشنری a رو به 1.0 تغییر بده (آپدیت کن).

خروجی
{'four': [4, 4.0], 'two': 'to', 'three': 3.0, 'one': 1.0}

جفت کلید-مقدار مربوط به کلید 'one' رو از دیکشنری a حذف کن.

خروجی
{'four': [4, 4.0], 'two': 'to', 'three': 3.0}

با استفاده از متد clear() همه‌ی جفت‌های کلید-مقدار رو از دیکشنری a پاک کن.

خروجی
{}

خود دیکشنری a رو با کلمه‌ی کلیدی del کلاً حذف کن.

خروجی
Traceback (most recent call last):
  File "C:\Users\YourName\Desktop\test.py", line 2, in <module>
    print(a)
NameError: name 'a' is not defined

مهمه یادت باشه که کلیدها در دیکشنری باید یکتا باشن؛ یعنی نمی‌تونی کلید تکراری داشته باشی. اما اگر کلید تکراری وارد کنی، پایتون به جای خطا دادن، آخرین مقداری که به اون کلید دادی رو در نظر می‌گیره و قبلی رو نادیده می‌گیره. بیا خودت ببین:

خروجی
icecream

مفهوم دیکشنری کامپرهنشن در پایتون

دیکشنری کامپرهنشن یه روش برای تبدیل یه دیکشنری به یه دیکشنری دیگه‌ست. در حین این تبدیل، می‌تونی آیتم‌های دیکشنری اصلی رو با شرایط خاصی وارد دیکشنری جدید کنی و در صورت نیاز، هر آیتم رو تغییر بدی.

یه کامپرهنشن خوب می‌تونه کدت رو خواناتر کنه. اما نکته اینجاست که نباید اون‌قدر پیچیده‌اش کنی که وقتی خواستی بخونیش، گیج بشی که اصلاً داره چیکار می‌کنه. همیشه باید اصل «سادگی و خوانایی» رو در نظر داشته باشی.

برای استفاده از دیکشنری کامپرهنشن در پایتون، باید بتونی به کلیدها (key) و مقادیر (value) یه دیکشنری دسترسی پیدا کنی.

چطوری می‌شه این کار رو کرد؟

خیلی راحت می‌تونی از متدهای داخلی خود پایتون استفاده کنی:

خروجی
dict_keys(['c', 'd', 'a', 'b'])
خروجی
dict_values([3, 4, 1, 2])

کد بالا یه دیکشنری پایتون به اسم dict1 با چهار جفت کلید-مقدار می‌سازه. وقتی متد keys() رو روی دیکشنری صدا می‌زنی، یه شیء نمایشی شامل همه‌ی کلیدهای دیکشنری برمی‌گردونه.

متد values() هم وقتی روی دیکشنری فراخوانی می‌شه، یه شیء نمایشی از تمام مقادیر موجود در دیکشنری بهت می‌ده.

هر دوی این اشیاء مثل مجموعه‌ها (sets) رفتار می‌کنن و می‌تونی ازشون برای انجام عملیات مربوط به مجموعه‌ها روی کلیدها و مقادیر استفاده کنی.

یادت باشه که ترتیب کلیدها و مقادیر در این اشیاء نمایشی، لزوماً همون ترتیبی نیست که به دیکشنری اضافه شدن.

تغییر دادن ساده‌ی مقادیر

بیا با یه دیکشنری کامپرهنشن ساده شروع کنیم:

خروجی
{'e': 10, 'a': 2, 'c': 6, 'b': 4, 'd': 8}

در کد بالا، ما یه دیکشنری جدید به اسم double_dict1 از روی dict1 ساختیم، با این تفاوت که هر مقدار رو دو برابر کردیم.

حتی می‌تونی کلیدها رو هم تغییر بدی. مثلاً بیا همون دیکشنری بالا رو بسازیم، ولی این بار اسم کلیدها رو هم تغییر بدیم.

خروجی
{'dd': 4, 'ee': 5, 'aa': 1, 'bb': 2, 'cc': 3}

استفاده از متد ()items

خب، حالا می‌دونی چطوری به همه‌ی کلیدها و مقادیر در یه دیکشنری دسترسی پیدا کنی. یه راه دیگه اینه که با استفاده از متد items() مستقیماً به هر جفت کلید-مقدار دسترسی داشته باشی:

خروجی
dict_items([('c', 3), ('d', 4), ('a', 1), ('b', 2)])

قالب کلی برای استفاده از دیکشنری کامپرهنشن در پایتون به این شکله:

این ساده‌ترین و پایه‌ای‌ترین قالبیه که می‌تونی ازش استفاده کنی. هرچی شرط‌های بیشتری بهش اضافه کنی، می‌تونه پیچیده‌تر و پیشرفته‌تر بشه.

استفاده از متد ()fromkeys

پایتون متد fromkeys() رو هم داره که بهت اجازه می‌ده دیکشنری‌هایی با مقادیر یکسان برای یه سری کلید مشخص بسازی. این متد وقتایی که می‌خوای یه دیکشنری با مقادیر پیش‌فرض ایجاد کنی خیلی به درد می‌خوره.

خروجی
{0: True, 1: True, 2: True, 3: True, 4: True}

در این مثال، متد fromkeys() یه دیکشنری می‌سازه که کلیدهاش اعدادی از 0 تا 4 هستن و به هر کدوم مقدار True داده شده. این روش برای کارهایی مثل آماده کردن دیکشنری‌ها برای آپدیت‌های بعدی یا پردازش‌های مختلف خیلی کار رو راحت می‌کنه.

چرا باید از دیکشنری کامپرهنشن استفاده کنیم؟

دیکشنری کامپرهنشن ابزار قدرتمندیه و می‌تونه جایگزین خوبی برای حلقه‌های for و توابع لامبدا باشه. با این حال، نمی‌شه همه‌ی حلقه‌های for رو به شکل کامپرهنشن نوشت، اما برعکسش صادقه؛ یعنی هر دیکشنری کامپرهنشنی رو می‌شه با یه حلقه‌ی for بازنویسی کرد.

فرض کن می‌خوای یه دیکشنری جدید بسازی که کلیدهاش اعداد زوج بین 0 تا 10 باشن و مقدارشون هم به توان دو رسیده باشه.

بیا ببینیم چطور می‌شه این مسئله رو هم با حلقه‌ی for و هم با دیکشنری کامپرهنشن حل کرد:

خروجی
{0: 0, 8: 64, 2: 4, 4: 16, 6: 36}
خروجی
{0: 0, 8: 64, 2: 4, 4: 16, 6: 36}

جایگزینی برای حلقه‌های for

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

نکته: برای آشنایی بیشتر با حلقه‌ها در پایتون، می‌تونی آموزش حلقه‌ها در پایتون فینکا رو بخونی.

جایگزینی برای توابع لامبدا

توابع لامبدا روشی برای نوشتن توابع کوچیک و بدون اسم هستن. این توابع یک‌بارمصرفن و فقط همون جایی که تعریف می‌شن کاربرد دارن. توابع لامبدا معمولاً در کنار توابعی مثل filter()، map() و reduce() استفاده می‌شن.

بیا یه مثال از تابع لامبدا در کنار تابع map() ببینیم:

خروجی
{'t2': -28.88888888888889, 't3': -23.333333333333336, 't1': -34.44444444444444, 't4': -17.77777777777778}

یه مثال کامل از دیکشنری کامپرهنشن

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

کد رو قدم به قدم بررسی می‌کنیم: اول از همه، به یه فرمول ریاضی نیاز داریم تا تبدیل فارنهایت به سلسیوس رو برامون انجام بده.

توی کد قبلی، این کار رو با کمک تابع لامبدا انجام دادیم. بعد این تابع رو به عنوان ورودی دادیم به تابع map() تا این عملیات رو روی تک‌تک عناصر لیست fahrenheit.values() اجرا کنه.

تابع values() یادته؟ همون تابعی که لیستی از مقادیر ذخیره‌شده در دیکشنری رو بهمون می‌داد.

چیزی که تا الان داریم یه لیست از دماها به سلسیوسه، اما ما نیاز داریم خروجی به شکل یه دیکشنری باشه.

پایتون یه تابع داخلی به اسم zip() داره که روی عناصر چند شیء قابل پیمایش (iterable) به صورت هم‌زمان حرکت می‌کنه. می‌تونی درباره‌ی zip() در این مستندات پایتون بیشتر بخونی.

در مثالی که زدیم، تابع zip عناصر fahrenheit.keys() و لیست celsius رو با هم ترکیب می‌کنه و بهت جفت‌های کلید-مقداری می‌ده که می‌تونی با تابع dict اون‌ها رو تبدیل به یه دیکشنری کنی؛ یعنی همون چیزی که دنبالش بودیم.

حالا بیا همین مسئله رو با دیکشنری کامپرهنشن حل کنیم:

خروجی
{'t2': -28.88888888888889, 't3': -23.333333333333336, 't1': -34.44444444444444, 't4': -17.77777777777778}

اینجا جزئیات کدی که بالا نوشتیم رو دقیق‌تر بررسی می‌کنیم:

  • یه دیکشنری به اسم fahrenheit با چهار جفت کلید-مقدار می‌سازیم که دماها رو بر حسب فارنهایت نشون می‌دن.
  • یه دیکشنری جدید به اسم celsius تعریف می‌کنیم.
  • از دیکشنری کامپرهنشن استفاده می‌کنیم تا روی دیکشنری fahrenheit پیمایش کنیم و دماها رو با فرمول (5/9) * (F-32) به سلسیوس تبدیل کنیم.
  • برای هر جفت کلید-مقدار در fahrenheit، کلید رو توی متغیر k و مقدار رو توی متغیر v می‌ریزیم.
  • دمای سلسیوس با همون فرمول بالا حساب می‌شه و به عنوان یه جفت کلید-مقدار جدید به دیکشنری celsius اضافه می‌شه.
  • در نهایت هم دیکشنری جدید یعنی celsius چاپ می‌شه.

همون‌طوری که می‌بینی، با دیکشنری کامپرهنشن می‌شه مسئله رو فقط در یه خط کد حل کرد؛ در حالی که در روش قبلی باید دو مرحله کار می‌کردی و طرز کار سه تا تابع (lambda، map() و zip()) رو هم بلد بودی.

به علاوه، کدی که با کامپرهنشن نوشته می‌شه خیلی قابل فهم‌تره. پس دیکشنری کامپرهنشن می‌تونه جایگزین خیلی خوبی برای توابع لامبدا باشه.

اضافه کردن شرط به دیکشنری کامپرهنشن

موقع حل مسائل خیلی وقت‌ها پیش میاد که نیاز داری شروطی رو هم در نظر بگیری. بیا ببینیم چطوری می‌تونی با اضافه کردن شرط‌ها به دیکشنری کامپرهنشن، کدت رو قدرتمندتر کنی.

استفاده از شرط if

فرض کن باید از روی یه دیکشنری، یه دیکشنری جدید بسازی ولی فقط عناصری رو برداری که مقدارشون از 2 بزرگ‌تره. این یعنی باید به همون قالب ساده‌ای که بالاتر یاد گرفتی، یه شرط اضافه کنی:

خروجی
{'e': 5, 'c': 3, 'd': 4}

همونطور که دیدی اصلاً سخت نبود! اما اگه چند تا شرط مختلف داشته باشیم چی؟

استفاده از چند شرط if

توی مثال بالا، فرض کن علاوه بر اینکه مقدار باید بزرگ‌تر از 2 باشه، باید چک کنی که مضربی از 2 هم باشه. در این حالت چیکار می‌کنی؟

خروجی
{'d': 4}

اضافه کردن چند شرط به کامپرهنشن خیلی راحته؛ فقط کافیه شرط‌ها رو یکی بعد از دیگری بنویسی. اما باید حواست باشه که دقیقاً می‌خوای چیکار کنی. یادت باشه که وقتی چند تا if رو پشت سر هم می‌نویسی، پایتون اون‌ها رو طوری اجرا می‌کنه که انگار بینشون and گذاشتی (یعنی باید همه‌ی شرط‌ها برقرار باشن).

بیا یه مثال دیگه با سه تا شرط رو ببینیم:

خروجی
{'f': 6}

اگه بخوای همین رو با یه حلقه‌ی for بنویسی، یه چیزی شبیه به این می‌شه:

خروجی
{'f': 6}

استفاده از شرط if-else

استفاده از شرط if-else در دیکشنری کامپرهنشن هم خیلی راحته. مثال زیر رو ببین تا دقیقاً متوجه بشی:

خروجی
{'f': 'even', 'c': 'odd', 'b': 'even', 'd': 'even', 'e': 'odd', 'a': 'odd'}

دیکشنری کامپرهنشن تودرتو

مفهوم «تو در تو» در برنامه‌نویسی یعنی سازمان‌دهی داده‌ها در لایه‌های مختلف؛ به این شکل که یه شیء شامل اشیاء مشابه دیگه‌ای داخل خودش باشه. احتمالاً تا حالا شرط‌های if تو در تو رو زیاد دیدی؛ یعنی یه if که داخل یه if دیگه نوشته شده.

دیکشنری‌ها هم دقیقاً می‌تونن تو در تو باشن و به همین خاطر، کامپرهنشن اون‌ها هم می‌تونه تو در تو نوشته بشه. بیا ببینیم این موضوع در عمل یعنی چی:

خروجی
{'first': {1.0}, 'second': {2.0}}

این یه مثال از دیکشنری تو در توئه. nested_dict یه دیکشنریه که کلیدهاش first و second هستن و مقادیرشون خودشون یه دیکشنری دیگه‌ان. کد ما روی مقادیر دیکشنری داخلی کار می‌کنه، اون‌ها رو اعشاری می‌کنه و بعد کلیدهای بیرونی رو با این مقادیر جدید ترکیب می‌کنه تا دیکشنری نهایی رو بسازه.

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

هرچی ساختار دیکشنریت پیچیده‌تر بشه، نوشتن کامپرهنشن براش هم سخت‌تر می‌شه. در این شرایط، بهتره بی‌خیال کامپرهنشن‌های خیلی پیچیده بشی و کد رو جور دیگه‌ای بنویسی.

توجه: می‌تونی کد بالا رو با یه حلقه‌ی for تو در تو هم به این شکل بنویسی:

خروجی
{'first': {'a': 1.0}, 'second': {'b': 2.0}}

حرف آخر

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

یادت نره که تمرین کردن تو رو تبدیل به یه برنامه‌نویس بهتر می‌کنه! برای بهتر شدن کدهات می‌تونی نکات و ترفندهای پایتون فینکا رو بخونی یا در مسیر آموزشی مبانی داده‌ها با پایتون شرکت کنی تا به مهم‌ترین مباحث مسلط بشی.

اشتراک‌گذاری
فهرست مطالب
  • دیکشنری پایتون چیه؟
  • مفهوم دیکشنری کامپرهنشن در پایتون
  • چرا باید از دیکشنری کامپرهنشن استفاده کنیم؟
  • یه مثال کامل از دیکشنری کامپرهنشن
  • اضافه کردن شرط به دیکشنری کامپرهنشن
  • حرف آخر

سوالات متداول

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

سینتکس دیکشنری کامپرهنشن در پایتون به این شکله: {key:value for (key,value) in iterable}

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

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

مهم‌ترین مزیت دیکشنری کامپرهنشن در پایتون اینه که کدها رو خلاصه و خواناتر می‌کنه و برای ساخت دیکشنری به کد کمتری نیاز داری. همچنین بهت اجازه می‌ده که فیلتر کردن و تغییر عناصر دیکشنری رو فقط در یه خط کد انجام بدی.

دریافت اپلیکیشن فینکا

با اپلیکیشن فینکا، به بیشتر دوره‌ها و مسیرها روی موبایل دسترسی دارید، تمرین می‌کنید و یادگیری رو هم‌زمان روی موبایل و دسکتاپ ادامه می‌دید.