آموزش پایتون, پایتون سطح متوسط

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

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)

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

  1. لیست توان سوم اعداد ۱ تا ۱۰ را بسازید.
  2. فقط اعداد فرد بین ۱ تا ۳۰ را انتخاب کنید.
  3. نام‌ها را با حذف فاصله‌های ابتدا و انتها و تبدیل به حالت عنوان استاندارد کنید.
  4. از یک لیست عددی، برچسب «مثبت»، «منفی» یا «صفر» بسازید.
  5. فقط رشته‌هایی را نگه دارید که طول آن‌ها بیشتر از چهار است.
  6. یک ماتریس سه‌درسه شامل حاصل‌ضرب شماره سطر و ستون بسازید.
  7. یک لیست تو‌در‌تو را به لیست ساده تبدیل کنید.
  8. از دو لیست نام و نمره، رشته‌های گزارش با zip() بسازید.
  9. از لیست محصولات، نام کالاهای فعال با قیمت کمتر از ۵۰۰ هزار را استخراج کنید.
  10. 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.

ادامه مسیر یادگیری پایتون

برای یادگیری منظم، آموزش‌های مرتبط زیر را به‌ترتیب دنبال کنید:

می‌خواهی پیشرفتت ذخیره شود؟با ورود یا ثبت‌نام رایگان، درس‌های تمام‌شده را علامت بزن و درصد پیشرفتت را در حساب کاربری ببین.ورود / ثبت‌نام برای ذخیره پیشرفت
درس بعدی · دوره پایتون متوسط (10 از 18)مدیریت خطا در پایتون با try، except، else و finally ←
آموزش‌های تازه، کد آماده و رفع خطاهر هفته در کانال Dev Source؛ رایگان.
🧭 مسیر یادگیری پایتون از صفر
ماژول 5: ساختارهای داده — درس 22 از 44

برای ذخیره پیشرفت در همه دستگاه‌ها و دریافت گواهی پایان مسیر، رایگان ثبت‌نام کن یا وارد شو.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *