توابع در پایتون
توابع در پایتون
۱. تابع چیست و چرا استفاده میشود؟
تا به این مرحله از یادگیری پایتون، انواع دادهها (اعداد، رشتهها، بولینها) و ساختارهای داده اصلی (لیست، تاپل، دیکشنری وعداد، رشتهها، بولینها) و ساختارهای داده اصلی (لیست، تاپل، دیکشنری و مجموعه) به همراه متدهای کاربردی آنها را یاد گرفتید. اکنون به یکی از مهمترین و بنیادینترین مفاهیم در برنامهنویسی یعنی توابع (Functions) میرسیم.
چرا به تابع نیاز داریم؟
در برنامهنویسی واقعی، وقتی برنامهها بزرگ میشوند، کدهای زیادی مینویسیم که ممکن است نیاز باشد چند بار در جاهای مختلف تکرار شوند. اگر نخواهیم کدها را کپیپیست کنیم و برنامه شلوغ نشود، از «تابع» استفاده میکنیم. تابع (Function) یک قطعه کد مستقل، سازمانیافته و دارای نام مشخص است که برای انجام یک کار مشخص طراحی میشود. تابع تا زمانی که آن را صدا نزنیم (Call نکنیم)، اجرا نمیشود.

چرا باید از تابع استفاده کنیم؟
- اصل DRY (Don’t Repeat Yourself): به جای نوشتن چندینباره یک عملیات، یکبار تابع را مینویسیم و هر کجا نیاز بود، با یک خط آن را فراخوانی میکنیم.
- خوانایی و نظم پروژه: برنامه بزرگ به بخشهای کوچک و معنادار (ماژولار) شکسته میشود.
- اشکالزدایی (Debugging) و نگهداری آسان: اگر مشکلی در محاسبات پیش بیاید، تنها کافی است بدنه همان تابع را ویرایش کنیم، نه کل پروژه را.
ساختار کلی تعریف تابع در پایتون
برای ساخت یک تابع در پایتون از کلمه کلیدی def (مخفف Define) استفاده میکنیم:
# ساختار کلی تعریف تابع در پایتون
def function_name(parameters):
# بدنه تابع
return output
۲. تابع بدون ورودی و بدون خروجی
گاهی تابعی مینویسیم که نیازی به دریافت داده از بیرون ندارد و قرار نیست نتیجهای را به متغیر دیگری برگرداند؛ تنها وظیفه آن چاپ یک پیام یا اجرای مجموعهای از کارهای ثابت است.
- صورت مسئله: میخواهیم تابعی بنویسیم که در ابتدای اجرای نرمافزار، بنر خوشآمدگویی و نسخه برنامه را برای کاربر چاپ کند.
# تعریف تابع
def show_welcome_message():
print("========================================")
print("به سیستم پردازش و تحلیل داده خوش آمدید!")
print("نسخه سیستم: v1.0.0")
print("========================================")
# فراخوانی تابع برای اجرا
show_welcome_message()
۳. تابع با ورودی و مقدار بازگشتی
یک تابع حرفهای دادههایی را به عنوان ورودی (Parameter / Argument) دریافت میکند، روی آنها پردازش انجام میدهد و سپس نتیجه را با کلیدواژه return برمیگرداند تا بتوان نتیجه را در متغیر ذخیره کرد یا در محاسبات بعدی به کار برد.

- صورت مسئله: میخواهیم تابعی بنویسیم که ابعاد یک مستطیل (طول و عرض) را بگیرد، مساحت آن را محاسبه کرده و مقدار مساحت را برگرداند.
# تعریف تابع با دو ورودی length و width
def calculate_rectangle_area(length, width):
area = length * width
return area # برگرداندن حاصل ضرب به عنوان نتیجه
# فراخوانی تابع و ذخیره مقدار برگشتی در یک متغیر
room_length = 12
room_width = 8
total_area = calculate_rectangle_area(room_length, room_width)
print("مساحت اتاق:", total_area) # خروجی: 96
۴. تعیین نوع دادهها ، مستندسازی و تابع help()
برای اینکه کد ما خوانا باشد و دیگر برنامهنویسان به راحتی از آن استفاده کنند:
- از Type Hinting استفاده میکنیم تا مشخص شود هر ورودی و خروجی باید از چه نوع دادهای باشد (مثلاً
floatیاstr). - از Docstring (توضیحات چندخطی داخل
""") استفاده میکنیم تا عملکرد تابع را مستند کنیم. پایتون با دستورhelp()این توضیحات را به کاربر نشان میدهد. - صورت مسئله: میخواهیم تابعی برای تبدیل دمای درجه سلسیوس به فارنهایت بنویسیم که نوع دادهها به وضوح مشخص باشد و راهنمای کامل داشته باشد.
def celsius_to_fahrenheit(celsius: float) -> float:
"""
این تابع دمای دریافت شده بر حسب سلسیوس را به فارنهایت تبدیل میکند.
فرمول: (Celsius * 9/5) + 32
پارامترها:
celsius (float): مقدار عددی دما به سلسیوس
خروجی:
float: مقدار معادل دما به فارنهایت
"""
fahrenheit = (celsius * 9 / 5) + 32
return fahrenheit
# استفاده از تابع
temp_c = 37.0
temp_f = celsius_to_fahrenheit(temp_c)
print(f"دمای {temp_c} سلسیوس برابر است با {temp_f} فارنهایت.")
# فراخوانی مستندات تابع در پایتون
print("\n--- مشاهده راهنمای تابع ---")
help(celsius_to_fahrenheit)
۵. اعتبارسنجی نوع داده و مدیریت خطا در تابع
پایتون زبانی پویا است و در حالت عادی نوع ورودی را اجبار نمیکند. اگر کاربری به جای عدد، رشته بفرستد، برنامه ممکن است در میان کار متوقف شود. بنابراین میتوانیم با تابع isinstance() نوع ورودی را بررسی کرده و در صورت اشتباه بودن، صراحتاً خطا (raise TypeError) ایجاد کنیم.
- صورت مسئله: میخواهیم تابعی بنویسیم که وزن (کیلوگرم) و قد (متر) کاربر را بگیرد و شاخص توده بدنی (BMI) را حساب کند. اگر ورودیها عددی نبودند یا قد صفر و منفی بود، خطای مناسب برگرداند.
def calculate_bmi(weight: float, height: float) -> float:
# ۱. بررسی نوع دادهها
if not isinstance(weight, (int, float)) or not isinstance(height, (int, float)):
raise TypeError("خطا: وزن و قد باید مقادیر عددی (int یا float) باشند!")
# ۲. بررسی منطق مقادیر
if height <= 0:
raise ValueError("خطا: قد باید عددی مثبت و بزرگتر از صفر باشد!")
# ۳. محاسبه فرمول BMI: وزن تقسیم بر مجذور قد
bmi = weight / (height ** 2)
return round(bmi, 2)
# اجرای درست
patient_bmi = calculate_bmi(75.5, 1.80)
print("شاخص BMI:", patient_bmi)
# مثال از تولید خطا در صورت ورودی نامعتبر (در صورت خارج کردن از کامنت):
# calculate_bmi("75", 1.80) # باعث ایجاد TypeError میشود
۶. مقادیر پیشفرض ورودی
گاهی میخواهیم برخی ورودیهای تابع اختیاری باشند؛ یعنی اگر کاربر مقداری برای آنها مشخص نکرد، پایتون خودکار از یک مقدار پیشفرض (Default Arguments) استفاده کند.
- صورت مسئله: میخواهیم تابعی بنویسیم که اطلاعات بیمار و بخش بستری را ثبت کند. بخش بستری پیشفرض
"اورژانس"باشد، مگر اینکه کاربر بخش دیگری را تعیین کند.
def register_patient(patient_name: str, age: int, ward: str = "اورژانس") -> str:
return f"بیمار {patient_name} ({age} ساله) در بخش '{ward}' پذیرش شد."
# ۱. فراخوانی بدون وارد کردن بخش (استفاده از مقدار پیشفرض)
print(register_patient("سارا محمدی", 28))
# ۲. فراخوانی با تغییر مقدار بخش
print(register_patient("علی کریمی", 45, ward="قلب و عروق"))
۷. آرگومانهای ترتیبی و کلیدواژهای
هنگام ارسال ورودی به تابع دو روش داریم:
- Positional Arguments (بر اساس موقعیت): مقادیر را دقیقاً به ترتیبی که در تعریف تابع آمده ارسال میکنیم.
- Keyword Arguments (بر اساس نام کلیدواژه): با ذکر نام پارامتر (
name=value) مقدار را ارسال میکنیم. در این روش، ترتیب قرارگیری پارامترها اهمیتی ندارد.
- صورت مسئله: تابعی برای ذخیره تنظیمات اتصال به پایگاه داده با سه متغیر میزبان (host)، پورت (port) و پروتکل (protocol) مینویسیم و آن را با هر دو روش فراخوانی میکنیم.
def setup_connection(host: str, port: int, protocol: str) -> str:
return f"اتصال به {protocol}://{host}:{port} با موفقیت تنظیم شد."
# روش اول: ترتیبی (Positional) - پایتون دادهها را بر اساس مکان میشناسد
config1 = setup_connection("localhost", 5432, "postgresql")
print("روش ترتیبی:", config1)
# روش دوم: کلیدواژهای (Keyword) - ترتیب به هم ریخته ولی نامها مشخص است
config2 = setup_connection(protocol="https", host="api.server.com", port=443)
print("روش کلیدواژهای:", config2)
۸. کد کامل و جامع
در این بخش، تمام مباحث آموزش دادهشده شامل Type Hinting، Docstring، اعتبارسنجی نوع داده و خطا، مقادیر پیشفرض و فراخوانی ترتیبی و کلیدواژهای را در یک مثال عملی و کامل جمعبندی میکنیم:
- صورت مسئله: تابعی مینویسیم که میزان مصرف داروی تجویزی برای یک بیمار را بر اساس وزن، دوز پایه و فاکتور سن محاسبه کند. تمام ورودیها باید اعتبارسنجی شده و برای سن پیشفرض بزرگسال در نظر گرفته شود.
def calculate_drug_dosage(
weight_kg: float,
base_dose_per_kg: float = 2.5,
is_pediatric: bool = False
) -> float:
"""
محاسبه دوز نهایی داروی تجویزی بر اساس مشخصات بیمار.
پارامترها:
weight_kg (float): وزن بیمار به کیلوگرم
base_dose_per_kg (float, optional): دوز مصرفی به ازای هر کیلوگرم (پیشفرض: 2.5 میلیگرم)
is_pediatric (bool, optional): آیا بیمار کودک است؟ (پیشفرض: False)
خروجی:
float: دوز نهایی دارو به میلیگرم
خطاها:
TypeError: در صورت ارسال نوع داده نامعتبر
ValueError: در صورت منفی یا صفر بودن وزن
"""
# ۱. بررسی نوع دادهها (Type Checking)
if not isinstance(weight_kg, (int, float)) or not isinstance(base_dose_per_kg, (int, float)):
raise TypeError("وزن و دوز پایه باید مقادیر عددی باشند.")
if not isinstance(is_pediatric, bool):
raise TypeError("پارامتر is_pediatric باید از نوع بولین (True یا False) باشد.")
# ۲. بررسی مقادیر منطقی
if weight_kg <= 0 or base_dose_per_kg <= 0:
raise ValueError("وزن و دوز پایه باید اعدادی مثبت و بزرگتر از صفر باشند.")
# ۳. منطق محاسبه
total_dose = weight_kg * base_dose_per_kg
# اگر بیمار کودک باشد، دوز دارو نصف محاسبه میشود
if is_pediatric:
total_dose *= 0.5
return round(total_dose, 2)
# ==========================================
# بخش اجرای برنامه و آزمایش سناریوهای مختلف
# ==========================================
# ۱. فراخوانی با مقادیر پیشفرض (فقط وزن ارسال میشود)
dose_adult = calculate_drug_dosage(70.0)
print(f"دوز داروی بزرگسال (۷۰ کیلو): {dose_adult} میلیگرم")
# ۲. فراخوانی با پارامترهای کلیدواژهای (Keyword Arguments) برای بیمار کودک
dose_child = calculate_drug_dosage(
weight_kg=20.0,
base_dose_per_kg=3.0,
is_pediatric=True
)
print(f"دوز داروی کودک (۲۰ کیلو): {dose_child} میلیگرم")
# ۳. نمایش مستندات کامل تابع با help
print("\n--- مستندات آموزشی تابع ---")
help(calculate_drug_dosage)
۳ قانون طلایی که هر برنامهنویس باید بداند:
- قانون تکمسئولیتی: هر تابع باید فقط یک کار مشخص را به بهترین شکل انجام دهد.
- پایان اجرا با
return: به محض اجرای دستورreturn، اجرای تابع در همان لحظه متوقف شده و کنترل به بیرون تابع بازمیگردد. - ترتیب تعریف پارامترها: در تعریف تابع، ابتدا پارامترهای اجباری (بدون مقدار پیشفرض) و سپس پارامترهای اختیاری (دارای پیشفرض) قرار میگیرند.
