List Comprehension در پایتون؛ ساخت لیستهای کوتاه و حرفهای

🗓 آخرین بهروزرسانی:
List Comprehension یکی از خواناترین روشهای پایتون برای ساخت لیستهای جدید از روی دادههای موجود است. با این ساختار میتوان بسیاری از حلقههای ساده، تبدیل دادهها و فیلترکردن عناصر را در یک عبارت کوتاه و قابل فهم نوشت.
این مطلب، درس نهم از دوره رایگان پایتون سطح متوسط است. در درس قبلی با توابع Lambda و کاربرد آنها در map()، filter() و مرتبسازی آشنا شدیم. اکنون روش پایتونیتر ساخت و تبدیل لیستها را بررسی میکنیم.
List Comprehension در پایتون چیست؟
List Comprehension یا «درک لیست» روشی فشرده برای ساخت یک لیست جدید از روی یک داده قابل پیمایش مانند لیست، تاپل، رشته، مجموعه یا خروجی range() است.
ساختار پایه:
new_list = [expression for item in iterable]expressionمقداری است که وارد لیست جدید میشود.itemمتغیر موقت هر تکرار است.iterableدادهای است که روی آن پیمایش انجام میشود.
نخستین مثال List Comprehension
روش معمول با حلقه:
squares = []
for number in range(1, 6):
squares.append(number ** 2)
print(squares)نسخه کوتاهتر با List Comprehension:
squares = [number ** 2 for number in range(1, 6)]
print(squares)خروجی:
[1, 4, 9, 16, 25]ترتیب خواندن List Comprehension
برای درک بهتر، عبارت زیر را از بخش حلقه بخوانید:
[number * 2 for number in numbers]یعنی: «برای هر number در numbers، مقدار number * 2 را در لیست جدید قرار بده.»
ساخت لیست از range
numbers = [number for number in range(1, 11)]
print(numbers)تبدیل عناصر یک لیست
prices = [100000, 250000, 400000]
prices_with_tax = [price * 1.09 for price in prices]
print(prices_with_tax)کار با رشتهها
names = ["mehran", "sara", "ali"]
formatted_names = [name.title() for name in names]
print(formatted_names)تبدیل نوع داده با List Comprehension
values = ["10", "20", "30"]
numbers = [int(value) for value in values]
print(numbers)فیلترکردن عناصر با if
برای انتخاب فقط برخی عناصر، شرط در انتهای ساختار قرار میگیرد:
new_list = [expression for item in iterable if condition]انتخاب اعداد زوج
even_numbers = [number for number in range(1, 21) if number % 2 == 0]
print(even_numbers)انتخاب نامهای بلند
names = ["علی", "مهران", "سارا", "محمدرضا"]
long_names = [name for name in names if len(name) >= 5]
print(long_names)حذف مقدارهای خالی
values = ["Python", "", None, "SQL", " ", "Git"]
clean_values = [value.strip() for value in values if isinstance(value, str) and value.strip()]
print(clean_values)تفاوت شرط فیلتر با عبارت شرطی
شرطی که در انتهای List Comprehension قرار میگیرد، مشخص میکند چه عناصری وارد خروجی شوند:
even_numbers = [number for number in numbers if number % 2 == 0]اما عبارت شرطی قبل از for مشخص میکند برای هر عنصر چه مقداری تولید شود:
labels = ["زوج" if number % 2 == 0 else "فرد" for number in numbers]if و else در List Comprehension
numbers = [3, -2, 0, 8, -5]
statuses = ["مثبت" if number > 0 else "صفر یا منفی" for number in numbers]
print(statuses)جایگزینکردن مقادیر نامعتبر
scores = [18, -2, 14, 25, 10]
valid_scores = [score if 0 <= score <= 20 else None for score in scores]
print(valid_scores)چند شرط در بخش فیلتر
numbers = [number for number in range(1, 51) if number % 2 == 0 if number % 3 == 0]
print(numbers)نسخه خواناتر با and:
numbers = [number for number in range(1, 51) if number % 2 == 0 and number % 3 == 0]List Comprehension روی رشته
text = "Python 3.14"
letters = [character for character in text if character.isalpha()]
print(letters)استفاده از تابع داخل List Comprehension
def normalize_name(name):
return name.strip().title()
names = [" mehran", "SARA ", " ali "]
clean_names = [normalize_name(name) for name in names]
print(clean_names)اگر منطق تبدیل چندمرحلهای است، قراردادن آن داخل یک تابع معمولی خوانایی را افزایش میدهد.
کار با لیستی از دیکشنریها
products = [
{"name": "کتاب", "price": 180000, "active": True},
{"name": "هدفون", "price": 950000, "active": False},
{"name": "ماوس", "price": 420000, "active": True}
]
active_names =
خرید و دانلود کتاب An Introduction to Statistical Learning (ISLR) ویرایش دوم اثر Gareth James و همکاران
قیمت اصلی ۸۹.۰۰۰ تومان بود.۴۵.۰۰۰ تومانقیمت فعلی ۴۵.۰۰۰ تومان است.
for product in products if product["active"]]
print(active_names)ساخت دیکشنریهای جدید
summaries = [
{
"name": product["name"],
"price_with_tax": product["price"] * 1.09
}
for product in products
if product["active"]
]
print(summaries)استفاده از enumerate
skills = ["Python", "Git", "SQL"]
numbered_skills = [f"{index}. {skill}" for index, skill in enumerate(skills, start=1)]
print(numbered_skills)استفاده از zip
names = ["علی", "سارا", "رضا"]
scores = [18, 20, 15]
reports = [f"{name}: {score}" for name, score in zip(names, scores)]
print(reports)حلقههای تودرتو در List Comprehension
میتوان بیش از یک حلقه در ساختار قرار داد:
pairs = [(x, y) for x in range(1, 4) for y in range(1, 3)]
print(pairs)نسخه معمولی این کد:
pairs = []
for x in range(1, 4):
for y in range(1, 3):
pairs.append((x, y))تختکردن لیست تودرتو
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
flat_numbers = [number for row in matrix for number in row]
print(flat_numbers)ساخت ماتریس با List Comprehension
matrix = [[row * column for column in range(1, 4)] for row in range(1, 4)]
for row in matrix:
print(row)List Comprehension تودرتو؛ چه زمانی مناسب نیست؟
ساختارهای تودرتو ممکن است سریعاً دشوار شوند. اگر برای فهم عبارت مجبورید چند بار آن را بخوانید، استفاده از حلقه معمولی یا تابع کمکی انتخاب بهتری است.
مقایسه List Comprehension با map
numbers = [1, 2, 3, 4]
with_map = list(map(lambda number: number ** 2, numbers))
with_comprehension = [number ** 2 for number in numbers]برای تبدیلهای ساده، List Comprehension معمولاً مستقیمتر و خواناتر است. map() زمانی مفید است که تابع آمادهای داریم یا میخواهیم از سبک تابعی استفاده کنیم.
مقایسه List Comprehension با filter
numbers = [1, 2, 3, 4, 5, 6]
with_filter = list(filter(lambda number: number % 2 == 0, numbers))
with_comprehension = [number for number in numbers if number % 2 == 0]مقایسه با حلقه معمولی
| ویژگی | List Comprehension | حلقه معمولی |
|---|---|---|
| کد کوتاه | بسیار مناسب | طولانیتر |
| تبدیل و فیلتر ساده | خوانا | خوانا اما مفصل |
| منطق چندمرحلهای | ممکن است پیچیده شود | مناسبتر |
| مدیریت خطا | محدود | آسانتر |
| دیباگ مرحلهای | دشوارتر | آسانتر |
List Comprehension همیشه سریعتر نیست
این ساختار اغلب برای عملیات ساده سریع و بهینه است، اما معیار اصلی انتخاب باید خوانایی و درستی کد باشد. برای دادههای بسیار بزرگ، ساخت کامل لیست ممکن است حافظه زیادی مصرف کند؛ در چنین شرایطی Generator Expression مناسبتر است.
مقدمه Generator Expression
با جایگزینکردن کروشه با پرانتز، یک مولد میسازیم:
numbers = (number ** 2 for number in range(1_000_000))
print(next(numbers))مولد مقدارها را در زمان نیاز تولید میکند و همه آنها را همزمان در حافظه نگه نمیدارد. Generatorها در درس جداگانهای با جزئیات بررسی خواهند شد.
Set Comprehension
names = ["Ali", "ali", "SARA", "sara"]
unique_names = {name.lower() for name in names}
print(unique_names)Dictionary Comprehension
squares = {number: number ** 2 for number in range(1, 6)}
print(squares)Tuple Comprehension وجود ندارد
عبارت زیر تاپل تولید نمیکند و یک Generator Expression میسازد:
values = (number ** 2 for number in range(5))
print(type(values))برای ساخت تاپل باید نتیجه را به tuple() بدهیم:
values = tuple(number ** 2 for number in range(5))مدیریت خطا در List Comprehension
قرار دادن try و except مستقیم در List Comprehension ممکن نیست. برای تبدیلهای خطاپذیر، از تابع کمکی استفاده کنید:
def to_integer(value):
try:
return int(value)
except (ValueError, TypeError):
return None
values = ["10", "abc", None, "25"]
numbers = [to_integer(value) for value in values]
print(numbers)خطاهای رایج
۱. جابهجایی expression و for
# نادرست
numbers = [for number in range(5) number * 2]۲. قراردادن if و else در جای اشتباه
# درست
labels = ["زوج" if number % 2 == 0 else "فرد" for number in numbers]۳. استفاده از List Comprehension فقط برای اثر جانبی
# نامناسب
[print(name) for name in names]برای چاپ یا تغییرات جانبی، حلقه معمولی خواناتر است:
for name in names:
print(name)۴. پیچیدهکردن بیش از حد عبارت
چند حلقه، چند شرط و چند تبدیل در یک خط میتواند نگهداری کد را دشوار کند. در این حالت عبارت را به چند مرحله یا تابع کمکی تقسیم کنید.
۵. تغییر لیست اصلی هنگام پیمایش
List Comprehension باید معمولاً یک لیست جدید بسازد. تغییر همزمان داده اصلی میتواند رفتار غیرقابل پیشبینی ایجاد کند.
پروژه اول: پاکسازی و اعتبارسنجی نمرات
raw_scores = ["18", " 15 ", "abc", "21", "9", None, "20"]
def parse_score(value):
try:
score = int(value)
except (ValueError, TypeError):
return None
if 0 <= score <= 20:
return score
return None
scores = [
score
for value in raw_scores
if (score := parse_score(value)) is not None
]
average = sum(scores) / len(scores) if scores else 0
print("نمرات معتبر:", scores)
print("میانگین:", average)در این پروژه دادههای نامعتبر حذف و میانگین نمرات معتبر محاسبه میشود. عبارت انتسابی := مقدار تابع را ذخیره میکند تا دوباره محاسبه نشود.
پروژه دوم: گزارش محصولات فعال و تخفیفدار
products = [
{"name": "کتاب", "price": 180000, "discount": 10, "active": True},
{"name": "هدفون", "price": 950000, "discount": 0, "active": False},
{"name": "ماوس", "price": 420000, "discount": 15, "active": True},
{"name": "کیبورد", "price": 780000, "discount": 5, "active": True}
]
report = [
{
"name": product["name"],
"original_price": product["price"],
"final_price": product["price"] * (1 - product["discount"] / 100)
}
for product in products
if product["active"] and product["discount"] > 0
]
for item in report:
print(item)تمرینهای درس
- لیست توان سوم اعداد ۱ تا ۱۰ را بسازید.
- فقط اعداد فرد بین ۱ تا ۳۰ را انتخاب کنید.
- نامها را با حذف فاصلههای ابتدا و انتها و تبدیل به حالت عنوان استاندارد کنید.
- از یک لیست عددی، برچسب «مثبت»، «منفی» یا «صفر» بسازید.
- فقط رشتههایی را نگه دارید که طول آنها بیشتر از چهار است.
- یک ماتریس سهدرسه شامل حاصلضرب شماره سطر و ستون بسازید.
- یک لیست تودرتو را به لیست ساده تبدیل کنید.
- از دو لیست نام و نمره، رشتههای گزارش با
zip()بسازید. - از لیست محصولات، نام کالاهای فعال با قیمت کمتر از ۵۰۰ هزار را استخراج کنید.
- Dictionary Comprehension بنویسید که هر کلمه را به طول آن نگاشت کند.
📌 همچنین بخوانید: بازار کار پایتون در ایران، دستورهای break، continue و pass در پایتون و ساخت ربات تلگرام با پایتون
پرسشهای متداول
آیا List Comprehension همیشه بهتر از حلقه for است؟
خیر. برای تبدیلها و فیلترهای ساده مناسب است؛ اما برای منطق چندمرحلهای، مدیریت خطا یا اثرات جانبی، حلقه معمولی خواناتر است.
آیا میتوان چند شرط استفاده کرد؟
بله. میتوان از and و or یا چند بخش if استفاده کرد، به شرط آنکه خوانایی حفظ شود.
تفاوت List Comprehension و Generator Expression چیست؟
List Comprehension همه خروجی را فوراً در یک لیست ذخیره میکند؛ Generator Expression مقدارها را بهتدریج تولید میکند و حافظه کمتری مصرف میکند.
آیا میتوان try و except را داخل آن نوشت؟
بهصورت مستقیم خیر. منطق خطاپذیر را در تابع کمکی قرار دهید و آن تابع را در عبارت فراخوانی کنید.
آیا Tuple Comprehension داریم؟
خیر. استفاده از پرانتز یک Generator Expression میسازد. برای تاپل باید از tuple() استفاده شود.
جمعبندی
List Comprehension ابزاری قدرتمند برای ساخت، تبدیل و فیلترکردن لیستهاست. ساختار مناسب آن کوتاه، خوانا و محدود به یک عملیات روشن است. هر زمان عبارت بیش از حد پیچیده شد، استفاده از حلقه معمولی یا تابع کمکی انتخاب حرفهایتری خواهد بود.
درس بعدی: مدیریت خطا در پایتون با try، except، else و finally.
ادامه مسیر یادگیری پایتون
برای یادگیری منظم، آموزشهای مرتبط زیر را بهترتیب دنبال کنید:
برای ذخیره پیشرفت در همه دستگاهها و دریافت گواهی پایان مسیر، رایگان ثبتنام کن یا وارد شو.