توابع
تعریف تابع در پایتون: 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))