توابع

تعریف تابع در پایتون: def، پارامتر، return و docstring

۴ دقیقه مطالعه · به‌روزرسانی ۲۲ مهر ۱۴۰۵

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

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

دو ایدهٔ بزرگ: تجزیه و انتزاع

  • تجزیه (Decomposition): یک مسئلهٔ بزرگ را به تکه‌های کوچک و مستقل تقسیم کنید. هر تابع یک کار مشخص انجام می‌دهد.
  • انتزاع (Abstraction): وقتی از یک تابع استفاده می‌کنید، لازم نیست بدانید داخلش چطور کار می‌کند؛ فقط باید بدانید چه می‌گیرد و چه می‌دهد.

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

ساختار تابع

def bigger(a, b):
    """دو عدد می‌گیرد و بزرگ‌ترشان را برمی‌گرداند."""
    if a > b:
        return a
    else:
        return b

result = bigger(12, 90)
print(result)
print(bigger(7, 3))

اجزای تابع:

جزء در مثال بالا توضیح
کلمهٔ کلیدی def مخفف define: «دارم چیزی تعریف می‌کنم»
نام bigger با همان قواعد نام‌گذاری متغیرها؛ معمولاً یک فعل
پارامترها (a, b) ورودی‌ها؛ می‌تواند خالی باشد: ()
دونقطه : مثل if و for
docstring """…""" توضیح تابع؛ اختیاری ولی بسیار توصیه‌شده
بدنه خطوط تورفته کاری که تابع انجام می‌دهد
return return a مقداری که به صداکننده برمی‌گردد

پارامتر و آرگومان

  • پارامتر اسمی است که در تعریف تابع می‌نویسیم: a و b.
  • آرگومان مقداری است که هنگام صدا زدن می‌دهیم: 12 و 90.

وقتی bigger(12, 90) را صدا می‌زنیم، پایتون a = 12 و b = 90 قرار می‌دهد، بدنه را اجرا می‌کند و مقدار return را جای bigger(12, 90) می‌گذارد.

⚠️ تعریف کردن یک تابع آن را اجرا نمی‌کند. def فقط به پایتون یاد می‌دهد این تابع چیست. کد داخلش فقط وقتی اجرا می‌شود که صدایش بزنید: bigger(12, 90).

docstring: مستندات داخل کد

رشته‌ای که درست زیر خط def می‌آید docstring است. پایتون آن را نگه می‌دارد و با help نمایشش می‌دهد:

def area(w, h):
    """
    مساحت یک مستطیل را محاسبه می‌کند.

    Args:
        w: عرض
        h: ارتفاع
    Returns:
        حاصل‌ضرب w در h
    """
    return w * h

help(area)

💡 در Jupyter و VS Code وقتی داخل پرانتز تابع هستید و Shift+Tab می‌زنید (یا نشانگر را روی نام تابع می‌برید)، همین docstring نمایش داده می‌شود. شما (و همکارانتان) شش ماه بعد از این عادت تشکر خواهید کرد.

مثال: عدد اول با تابع

در تمرین‌های حلقه کد تشخیص عدد اول را نوشتیم. حالا آن را در یک تابع می‌گذاریم که True یا False برگرداند:

def is_prime(n):
    """اگر n عدد اول باشد True و در غیر این صورت False برمی‌گرداند."""
    if n < 2:
        return False
    for j in range(2, n):
        if n % j == 0:
            return False
    return True

print(is_prime(12), is_prime(13), is_prime(2), is_prime(90))

ببینید return False داخل حلقه چه کرد: به محض پیدا شدن یک مقسوم‌علیه، کل تابع تمام می‌شود و دیگر لازم نیست break بنویسیم یا پرچم نگه داریم. اگر حلقه تا آخر رفت و هیچ returnی اجرا نشد، یعنی هیچ مقسوم‌علیهی نبود: return True.

حالا چاپ همهٔ اعداد اول تا n، که قبلاً حلقهٔ تودرتوی شلوغی بود، این‌قدر خوانا می‌شود:

def is_prime(n):
    if n < 2:
        return False
    for j in range(2, n):
        if n % j == 0:
            return False
    return True

limit = 50
for i in range(2, limit + 1):
    if is_prime(i):
        print(i, end=" ")

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

مثال: ریشهٔ دوم با تابع

الگوریتم دوبخشی را هم می‌شود یک بار در تابع گذاشت و همه‌جا استفاده کرد:

def sqrt_bisection(x, epsilon=0.00000001):
    """ریشهٔ دوم x (x >= 0) را با روش دوبخشی تقریب می‌زند."""
    low = 0.0
    high = max(x, 1.0)
    ans = (high + low) / 2.0
    while abs(ans ** 2 - x) >= epsilon:
        if ans ** 2 < x:
            low = ans
        else:
            high = ans
        ans = (high + low) / 2.0
    return round(ans, 3)

print(sqrt_bisection(190))
print(sqrt_bisection(25))
a = sqrt_bisection(90)
print(a)

(epsilon=0.00000001 یعنی «اگر کسی مقدار نداد، این را بگذار». در درس آرگومان‌ها مفصل می‌بینیمش.)

تمرین

۱. زوج یا فرد

تابع is_even(n) بنویسید که اگر n زوج بود True و در غیر این صورت False برگرداند. یک docstring هم برایش بنویسید.

جواب
def is_even(n):
    """اگر n زوج باشد True برمی‌گرداند."""
    return n % 2 == 0

print(is_even(4), is_even(7))

نیازی به if نیست: n % 2 == 0 خودش True یا False است و مستقیم برمی‌گردد.

۲. فاکتوریل

تابع factorial(k) بنویسید و با آن 5! و 10! را چاپ کنید.

جواب
def factorial(k):
    """k! را برمی‌گرداند (k >= 0)."""
    result = 1
    for i in range(2, k + 1):
        result *= i
    return result

print(factorial(5), factorial(10))