توابع (Functions)؛ وقتی به پایتون یاد می‌دی کاراتو اتوماتیک انجام بده
تا اینجا کلی چیز یاد گرفتیم: متغیر ساختی، شرط گذاشتی، حلقه زدی، داده‌ها رو توی لیست و دیکشنری مرتب کردی. اما یه مشکل هست: هر بار که خواستی یه کار تکراری انجام بدی، مجبوری کل کد رو دوباره بنویسی. اینجاست که توابع مثل یه ناجی سر می‌رسن و می‌گن: «داداش، یه بار این کار رو به من یاد بده، دفعه‌های بعد فقط اسمم رو صدا کن، بقیه‌اش با من.»

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

چرا تابع؟ از تکرار خسته نشدی؟
فرض کن می‌خوای تو برنامه‌ات چند بار مساحت دایره رو حساب کنی:


# بدون تابع - هر بار باید کد رو تکرار کنی
r = 5
area1 = 3.14 * r * r
print(area1)

r = 7
area2 = 3.14 * r * r
print(area2)

r = 10
area3 = 3.14 * r * r
print(area3)


حالا ببین با تابع چقدر شیک‌تر می‌شه:


def area_of_circle(radius):
    return 3.14 * radius * radius

print(area_of_circle(5))
print(area_of_circle(7))
print(area_of_circle(10))


فواید تابع رو ببین:

جلوگیری از تکرار (DRY: Don't Repeat Yourself): یه بار می‌نویسی، بارها صدا می‌زنی.

خوانایی: اسم تابع می‌گه داری چیکار می‌کنی، لازم نیست کد رو خط به خط بخونی.

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

قابلیت استفادهٔ مجدد: تابع رو می‌تونی توی پروژه‌های دیگه هم کپی کنی.

ساخت تابع با def – بیا اینجا، یه کار بهت یاد بدم
برای تعریف تابع از کلمهٔ کلیدی def (مخفف define) استفاده می‌کنی. قالب کلی:


def name_of_function(parameters):
    """توضیح کوتاه دربارهٔ تابع (Docstring)"""
    # بدنهٔ تابع
    return value  # اختیاری


مثال ساده:

def greet():
    """یه سلام ساده چاپ می‌کنه."""
    print("سلام! خوش اومدی به دنیای پایتون.")

greet()  # صدا زدن تابع
greet()  # هر چند بار که بخوای


دقت کن:

بعد از اسم تابع حتماً پرانتز می‌ذاری (حتی اگه ورودی نداشته باشه).

دو نقطه : و تورفتگی مثل همیشه هستن.

Docstring (رشتهٔ توضیحی بین سه کوتیشن) اختیاری ولی شدیداً توصیه می‌شه.

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


def greet_person(name):
    """به شخص خاصی سلام می‌کنه."""
    print(f"سلام {name} جان! حالت چطوره؟")

greet_person("سارا")   # سلام سارا جان! حالت چطوره؟
greet_person("امیر")   # سلام امیر جان! حالت چطوره؟


چندتا پارامتر:


def introduce(name, age, city):
    print(f"من {name} هستم، {age} سالمه، اهل {city}.")

introduce("نرگس", 25, "شیراز")


ترتیب مهمه! "نرگس" می‌ره توی name، 25 می‌ره توی age، "شیراز" می‌ره توی city. به این می‌گن آرگومان‌های موقعیتی (Positional Arguments).

آرگومان‌های کلیدواژه‌ای – با اسم صدا بزن، نه با ردیف
اگه حوصله نداری ترتیب رو حفظ کنی، می‌تونی با اسم پارامتر مقدار رو بدی. اینطوری ترتیب دیگه مهم نیست:


introduce(age=25, city="تهران", name="بهار")
# من بهار هستم، 25 سالمه، اهل تهران.


می‌تونی ترکیبی هم استفاده کنی، ولی اول آرگومان‌های موقعیتی، بعد کلیدواژه‌ای:


introduce("بهار", city="تهران", age=25)  # درسته
# introduce(name="بهار", 25, "تهران")   # خطا! موقعیتی نباید بعد از کلیدواژه‌ای بیاد


مقدار پیش‌فرض – اگه چیزی نگفتی، خودم حدس می‌زنم
بعضی وقتا می‌خوای یه پارامتر اختیاری باشه و اگه کاربر مقداری نداد، یه مقدار پیش‌فرض داشته باشه:


def order_coffee(size="medium", sugar=True):
    """سفارش قهوه با تنظیمات پیش‌فرض"""
    sugar_text = "با شکر" if sugar else "بدون شکر"
    print(f"قهوهٔ {size}، {sugar_text}.")

order_coffee()                    # قهوهٔ medium، با شکر.
order_coffee("large")             # قهوهٔ large، با شکر.
order_coffee("small", False)      # قهوهٔ small، بدون شکر.
order_coffee(sugar=False)         # قهوهٔ medium، بدون شکر.


نکتهٔ مهم: پارامترهای پیش‌فرض باید بعد از پارامترهای اجباری بیان. این غلطه: def f(a=5, b):.

نکتهٔ خطرناک: از لیست یا دیکشنری خالی به‌عنوان مقدار پیش‌فرض استفاده نکن! چون همون آبجکت بین فراخوانی‌ها به اشتراک گذاشته می‌شه. به‌جاش از None استفاده کن:


# غلط
def add_item(item, my_list=[]):
    my_list.append(item)
    return my_list

# درست
def add_item(item, my_list=None):
    if my_list is None:
        my_list = []
    my_list.append(item)
    return my_list


return-از نتیجه دوباره استفاده کن
تابع می‌تونه یه نتیجه رو برگردونه تا بعداً ازش استفاده کنی. return این کار رو می‌کنه و همزمان تابع رو تموم می‌کنه. هر چیزی بعد از return اجرا نمی‌شه.


def add(a, b):
    return a + b

result = add(5, 3)
print(result)          # 8
print(add(10, 20))     # 30

# تابع بدون return، None برمی‌گردونه
def no_return():
    print("من چیزی برنمی‌گردونم")

x = no_return()  # "من چیزی برنمی‌گردونم" چاپ می‌شه
print(x)         # None


می‌تونی چندین مقدار رو با کاما جدا برگردونی که عملاً یه تاپل می‌شه:


def min_max(nums):
    return min(nums), max(nums)

low, high = min_max([5, 2, 9, 1, 7])  # Unpacking
print(low, high)   # 1 9


حوزهٔ متغیرها (Scope) – متغیر محلی در مقابل متغیر سراسری
متغیری که داخل تابع تعریف می‌شه، محلی (Local) هست و بیرون از تابع وجود نداره. انگار که فقط توی اتاق خودش زندگی می‌کنه. متغیرهای سراسری (Global) هم بیرون از همهٔ توابع تعریف می‌شن و همه جا قابل دیدن هستن.


global_var = "من همه جا هستم"

def my_func():
    local_var = "من فقط اینجام"
    print(global_var)   # دسترسی به متغیر سراسری
    print(local_var)

my_func()
# print(local_var)      # خطا! NameError: local_var وجود نداره


اگه داخل تابع بخوای یه متغیر سراسری رو تغییر بدی (نه فقط بخونی)، باید با global اعلام کنی:


counter = 0

def increment():
    global counter
    counter += 1

increment()
print(counter)   # 1


ولی بهتره حتی‌الامکان از global فرار کنی. به‌جاش با return مقدار رو برگردون و توی متغیر بیرونی بریز. اینطوری کدت تمیزتر و قابل‌پیش‌بینی‌تر می‌شه.

*args و **kwargs – هر چندتا ورودی که دلت خواست
اگه نمی‌دونی چندتا آرگومان قراره به تابع پاس داده بشه، دو تا قهرمان داری:

*args : تعداد نامشخصی آرگومان موقعیتی رو به صورت تاپل جمع می‌کنه.

**kwargs : تعداد نامشخصی آرگومان کلیدواژه‌ای رو به صورت دیکشنری جمع می‌کنه.

اسم args و kwargs قرارداده، ولی همه جا استفاده می‌شه. ستاره‌ها اصل کار رو انجام می‌دن.


def sum_all(*args):
    """هر چندتا عدد بدی، جمع می‌کنه"""
    total = 0
    for num in args:
        total += num
    return total

print(sum_all(1, 2, 3))           # 6
print(sum_all(5, 10, 15, 20))     # 50
print(sum_all())                  # 0



def print_info(**kwargs):
    """هر چی مشخصات بدی، چاپ می‌کنه"""
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_info(name="رضا", job="برنامه‌نویس", age=28)
# name: رضا
# job: برنامه‌نویس
# age: 28


ترکیبشون:


def universal_function(*args, **kwargs):
    print("آرگومان‌های موقعیتی:", args)
    print("آرگومان‌های کلیدواژه‌ای:", kwargs)

universal_function(1, 2, 3, name="پایتون", version=3.12)


توابع لامبدا (Lambda) – توابع یک‌خطی و جمع‌وجور
بعضی وقتا یه تابع خیلی ساده می‌خوای که ارزش def کردن چندخطی رو نداره. لامبدا یه تابع بی‌نام یک‌خطی‌ست که مستقیماً در عبارات استفاده می‌شه. قالبش:


lambda arguments: expression



# تابع معمولی
def square(x):
    return x * x

# معادل لامبدا
square_lambda = lambda x: x * x

print(square(5))        # 25
print(square_lambda(5)) # 25


کاربرد واقعی: داخل توابعی مثل sorted, map, filter:


 students = [("سارا", 18), ("امیر", 15), ("نرگس", 20)]
# مرتب‌سازی بر اساس نمره (عنصر دوم)
sorted_students = sorted(students, key=lambda student: student[1])
print(sorted_students)  # [('امیر', 15), ('سارا', 18), ('نرگس', 20)]


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

داکیومنت کردن تابع (Docstring) – به آینده‌ات لطف کن
همون رشتهٔ توضیحی اول تابع که گفتیم خیلی مهمه. بعداً که برگردی به کدت، یا یکی دیگه کدت رو ببینه، با help() می‌تونه بفهمه تابع چیکار می‌کنه:


def calculate_bmi(weight_kg, height_m):
    """محاسبهٔ شاخص تودهٔ بدنی (BMI).
    
    Args:
        weight_kg: وزن به کیلوگرم
        height_m: قد به متر
    
    Returns:
        عدد BMI
    """
    return weight_kg / (height_m ** 2)

help(calculate_bmi)


خروجی help یه راهنمای تمیز و خوشگل نشون می‌ده.

یه نمایش باحال: رستوران کوچیک با توابع
بیایم یه برنامهٔ سادهٔ سفارش غذا رو با همهٔ مفاهیمی که یاد گرفتیم بسازیم:


 MENU = {
    "پیتزا": 80_000,
    "همبرگر": 65_000,
    "سالاد": 45_000,
    "نوشابه": 15_000
}

def show_menu():
    """منوی رستوران رو چاپ می‌کنه."""
    print("🍕 منوی رستوران:")
    for item, price in MENU.items():
        print(f"  - {item}: {price:,} تومان")
    print("-" * 30)

def take_order(*items):
    """سفارش‌ها رو دریافت می‌کنه و قیمت کل رو برمی‌گردونه.
    
    Args:
        *items: نام غذاهای سفارش داده شده
    
    Returns:
        tuple: (لیست سفارش‌های معتبر، قیمت کل)
    """
    valid_orders = []
    total = 0
    for item in items:
        price = MENU.get(item)
        if price:
            valid_orders.append(item)
            total += price
        else:
            print(f"⚠️ ببخشید، {item} نداریم!")
    return valid_orders, total

def apply_discount(total, is_member=False, coupon=None):
    """تخفیف روی قیمت اعمال می‌کنه.
    
    Args:
        total: مبلغ کل
        is_member: آیا مشتری عضو ویژه‌ست؟
        coupon: کد تخفیف (اختیاری)
    
    Returns:
        مبلغ نهایی
    """
    discount = 0
    if is_member:
        discount += 0.1  # ۱۰٪ تخفیف عضویت
    if coupon == "TAVON20":
        discount += 0.2  # ۲۰٪ تخفیف کوپن
    return total * (1 - discount)

# اجرای رستوران
show_menu()

order_items, price = take_order("پیتزا", "همبرگر", "سوشی", "نوشابه")
print(f"سفارش‌های شما: {', '.join(order_items)}")
print(f"قیمت کل: {price:,} تومان")

final_price = apply_discount(price, is_member=True, coupon="TAVON20")
print(f"💰 مبلغ نهایی بعد از تخفیف: {final_price:,.0f} تومان")


همه رو یه جا دیدیم: def، پارامترها، *args، **kwargs (با coupon=None)، return چندتایی، متغیرهای محلی، و داکیومنت. رستوران ما با توابع مرتب و خوشگل شده.

جمع‌بندی: کدت رو ماژولار کن، زندگیت رو راحت
توابع قلب تپندهٔ برنامه‌نویسی مدرن هستن. بهت اجازه می‌دن کد رو توی بسته‌های کوچک و منطقی مرتب کنی، از تکرار بیهوده جلوگیری کنی، و مثل یه آشپز حرفه‌ای، هر بخش از برنامه رو جداگانه بپزی و بعد همه رو باهم سرو کنی.

یادت باشه:

هر تابع فقط یه کار رو خوب انجام بده.

اسمش رو معنی‌دار انتخاب کن.

پارامترهای زیاد رو توی *args و **kwargs مخفی نکن مگه اینکه واقعاً لازم باشه.

مقدار پیش‌فرض رو هوشمندانه بذار.

همیشه فکر کن: «این تابع چی می‌گیره، چیکار می‌کنه، چی برمی‌گردونه؟»

حالا که توابع رو یاد گرفتی، می‌تونی برنامه‌هات رو مثل لگو، تکه‌تکه و منظم بسازی. برو و کدهای تکراری رو بکش بیرون، بذار توی تابع، و ببین چقدر دنیات مرتب‌تر می‌شه! 🧩🐍✨