آموزش

توابع پایتون: چطور توابع رو فراخوانی کنیم و بنویسیم

یاد می‌گیری چطور تابع‌های پایتونی قابل‌استفاده‌مجدد و کارآمد بنویسی. به پارامترها، دستورهای return و موضوعات پیشرفته‌تری مثل تابع‌های lambda مسلط می‌شی. همچنین با استفاده از main و برخی نکات کدنویسی، کدت رو بهتر سازمان‌دهی می‌کنی.

تاریخ انتشار:
7 شهریور 1405
پایتون
14 دقیقه
تحلیل داده
کاربرهای فینکا در چه شرکت‌هایی مشغول به کار هستند؟

توابع بخش خیلی مهمی از زبان برنامه‌نویسی پایتون هستن. احتمالاً تا الان با یه سری از توابع کاربردی خود پایتون یا کتابخونه‌هاش کار کردی. اما به‌عنوان یه دانشمند داده، خیلی وقت‌ها مجبوری توابع خودت رو بنویسی تا بتونی چالش‌های مربوط به داده‌هات رو حل کنی.

برای تمرین بیشتر روی نوشتن توابع در پایتون، می‌تونی این تمرین عملی فینکا رو انجام بدی یا دوره ابزار علم داده پایتون ما رو ببینی!

توابع در پایتون

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

در پایتون سه نوع تابع داریم:

  • توابع داخلی، مثل help() برای دیدن راهنما، min() برای پیدا کردن کمترین مقدار، print() برای چاپ کردن چیزی و غیره. می‌تونی لیست کاملشون رو اینجا ببینی.

  • توابعی که کاربر می‌سازه تا کارهای خاص خودش رو پیش ببره.

  • توابع ناشناس که بهشون توابع لامبدا هم می‌گن، چون برای تعریفشون به جای def از کلمه‌های کلیدی متفاوتی استفاده می‌شه.

تفاوت توابع و متدها

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

به این مثال دقت کن؛ اول یه تابع به اسم plus() تعریف شده و بعدش یه کلاس به اسم Summation ساخته شده که متدی به اسم sum() داره:

حالا اگه بخوای متد sum() که داخل کلاس Summation هست رو صدا بزنی، اول باید یه نمونه از اون کلاس بسازی. پس بیا این کار رو بکنیم:

یادت نره که برای صدا زدن تابع plus() اصلا نیازی به این نمونه‌سازی‌ها نداری!

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

پارامترها همون اسم‌هایی هستن که موقع نوشتن و تعریف یه تابع یا متد استفاده می‌شن. اما آرگومان‌ها اون مقادیر واقعی‌ای هستن که موقع فراخوانی تابع یا متد، بهش پاس داده می‌شن. یعنی وقتی تابع رو صدا می‌زنی، مقادیری که بهش می‌دی می‌شن آرگومان، و تابع این مقادیر رو روی پارامترهاش تنظیم می‌کنه.

دوباره به کدهای بالا نگاه کن: موقع صدا زدن متد sum() در کلاس Summation، تو فقط دو تا آرگومان بهش پاس دادی؛ در حالی که موقع تعریف متد، سه تا پارامتر نوشته بودی: self، a و b.

پس چه اتفاقی برای self افتاد؟

اولین آرگومان هر متدی در پایتون، همیشه یه اشاره‌گر به نمونه فعلی اون کلاسه که در این مثال همون شیء ساخته‌شده از Summation هست. طبق یه قرارداد استاندارد، اسم این پارامتر رو همیشه self می‌ذارن.

معنیش اینه که موقع صدا زدن متدها، نیازی نیست self رو خودت پاس بدی؛ چون پایتون به صورت خودکار نمونهٔ فعلی رو به عنوان اولین پارامتر به متد پاس می‌ده.

چطور یه تابع بسازیم؟ (توابع تعریف‌شده توسط کاربر)

برای ساختن یه تابع در پایتون، ۴ تا مرحلهٔ اصلی رو باید طی کنی:

  1. اول کلمه کلیدی def رو می‌نویسی و بعدش اسم تابع رو میاری.

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

  3. دستوراتی که قراره تابع اجرا کنه رو با رعایت فاصله‌گذاری می‌نویسی.

  4. اگه قراره تابع خروجی خاصی داشته باشه، کدت رو با دستور return تموم می‌کنی. اگه return ننویسی، تابع در نهایت مقدار None رو برمی‌گردونه.

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

در تابعی که بالاتر دیدی، از کاربر خواسته می‌شه اسمش رو وارد کنه. اگه چیزی تایپ نکنه، تابع "Hello World" رو چاپ می‌کنه. اما اگه اسمش رو بنویسه، یه پیام اختصاصی مثل "Hello" به همراه اسمش نمایش داده می‌شه.

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

دستور return

دقت کن؛ وقتی در تابع hello() مستقیما داری چیزی رو چاپ می‌کنی (با print)، دیگه نیازی نیست مقداری رو return کنی. در واقع هیچ فرقی بین تابع بالا و این تابعی که در زیر نوشته شده وجود نداره:

اما اگه می‌خوای از نتیجه تابعت در جای دیگه‌ای کدت استفاده کنی و روش تغییری بدی، حتما باید از return استفاده کنی تا یه مقدار واقعی (مثل رشته، عدد و...) برگردونده بشه. به این مثال دقت کن؛ تابع hello() کلمه "hello" رو برمی‌گردونه اما تابع hello_noreturn() مقدار خروجی نداره و در واقع None برمی‌گردونه:

خروجی
Hello World
Traceback (most recent call last):
  File "<python-input-10>", line 1, in <module>
    hello_noreturn() * 2
    ~~~~~~~~~~~~~~~~~^~~
TypeError: unsupported operand type(s) for *: 'NoneType' and 'int'

فراخوانی تابع دوم بهت ارور می‌ده، چون نمی‌تونی هیچ عملیات ریاضی‌ای روی مقدار None انجام بدی. اینجاست که یه ارور از نوع TypeError می‌گیری که می‌گه قادر نیستی NoneType (که همون خروجی تابع دومه) رو در عدد صحیح یا همون int ضرب کنی.

نکته: به محض اینکه برنامه به خط return برسه، بلافاصله از تابع خارج می‌شه؛ حتی اگه جلوی return هیچ مقداری نوشته نشده باشه:

یه نکته جالب دیگه در مورد return اینه که باهاش می‌تونی چندین مقدار رو هم‌زمان برگردونی. برای این کار، پایتون از تاپل‌ها استفاده می‌کنه.

حواست باشه که تاپل خیلی شبیه به لیسته و می‌تونه شامل چند تا مقدار باشه؛ اما فرقی که داره اینه که تاپل‌ها غیرقابل‌تغییر هستن. یعنی نمی‌تونی مقادیر داخلشون رو بعداً عوض کنی! تاپل‌ها با پرانتز () ساخته می‌شن. موقع استفاده هم می‌تونی خروجی تابع رو با کمک کاما، مستقیماً داخل چند تا متغیر مجزا ذخیره کنی.

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

دقت کن که نوشتن return sum, a دقیقا همون کار return (sum, a) رو انجام می‌ده. در حالت اول، پایتون خودش به‌صورت خودکار در پس‌زمینه اون مقادیر رو تبدیل به یه تاپل می‌کنه.

چطور یه تابع رو صدا بزنیم (فراخوانی کنیم)؟

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

مثلا تابع hello() که تازه ساختی رو می‌تونی خیلی راحت با اجرای hello() صدا بزنی، دقیقاً مثل کد زیر:

اضافه کردن داک‌استرینگ به تابع

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

داک‌استرینگ‌ها درست بعد از خط تعریف تابع نوشته می‌شن و اون‌ها رو داخل سه تا علامت نقل‌قول جفتی قرار می‌دیم. مثلاً برای تابع hello() می‌تونی چنین چیزی بنویسی: Prints "Hello World".

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

انواع آرگومان‌های تابع در پایتون

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

  • آرگومان‌های پیش‌فرض
  • آرگومان‌های اجباری
  • آرگومان‌های کلمه‌کلیدی
  • آرگومان‌هایی با تعداد متغیر

آرگومان‌های پیش‌فرض

این نوع آرگومان‌ها یه مقدار اولیه‌ی پیش‌فرض دارن. یعنی اگه موقع فراخوانی تابع مقداری براشون در نظر نگیری، تابع خودش اون مقدار پیش‌فرض رو به‌جاش استفاده می‌کنه. برای تخصیص این مقدار هم کافیه از علامت مساوی = موقع تعریف پارامتر استفاده کنی، درست مثل مثال زیر:

آرگومان‌های اجباری

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

برای اینکه اروری نگیری، حتما باید دو تا آرگومان دلخواه به پارامترهای a و b اختصاص بدی. در این مثال اگه جای a و b رو عوض کنی (یعنی b+a)، در نتیجه نهایی تغییری ایجاد نمی‌شه. ولی اگه تابع plus() رو به شکل زیر تغییر بدی، دیگه ترتیبشون به شدت مهمه و نتیجه متفاوت می‌شه:

آرگومان‌های کلمه‌کلیدی

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

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

آرگومان‌های متغیر

خیلی وقت‌ها ممکنه از قبل ندونی که دقیقاً قراره چند تا آرگومان به تابع پاس بدی. در همچین شرایطی می‌تونی از کلمهٔ کلیدی *args مشابه روش زیر استفاده کنی:

گذاشتن یه علامت ستاره (*) قبل از اسم متغیر باعث می‌شه تا تمام آرگومان‌هایی که بعداً به تابع پاس می‌دی در اون ذخیره بشن. حواست باشه که نوشتن کلمهٔ args هیچ الزامی نداره؛ می‌تونی اسمش رو بذاری *varint یا *my_args و تابع plus() باز هم بدون مشکل کار می‌کنه.

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

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

متغیرهای سراسری در مقایسه با محلی

به زبون خیلی ساده، متغیرهایی که داخل دندونه‌های یه تابع تعریف می‌شن، «محلی» یا Local هستن و فقط داخل همون تابع معنی دارن و شناخته می‌شن. در مقابل، متغیرهایی که بیرون تابع تعریف می‌شن «سراسری» یا Global هستن و همهٔ توابعی که در کد نوشتی می‌تونن بهشون دسترسی داشته باشن و ازشون استفاده کنن.

همون‌طور که دیدی، وقتی خواستی متغیر محلی total که داخل خود تابع تعریف شده بود رو چاپ کنی، برنامه یه خطای NameError داد و گفت name 'total' is not defined (یعنی این متغیر شناخته‌شده نیست). اما متغیر init چون قبلش به‌صورت سراسری تعریف شده بود، خیلی راحت و بدون دردسر چاپ شد.

توابع ناشناس در پایتون

توابع ناشناس در پایتون بیشتر با اسم «تابع لامبدا» شناخته می‌شن. دلیلش هم اینه که برای تعریفشون به جای def از کلمهٔ کلیدی lambda استفاده می‌کنیم.

در قطعه کدی که دیدی، قسمت lambda x: x*2 دقیقا همون تابع ناشناس ماست. x نقشه آرگومان رو داره و x*2 همون عبارتیه که پردازش می‌شه و نتیجه‌اش برمی‌گرده. مهم‌ترین ویژگی این توابع اینه که اصلاً اسمی ندارن (برخلاف توابعی که در بخش‌های قبلی با def می‌ساختی). اگه می‌خواستی همین منطق رو با یه تابع معمولی بنویسی، به این شکل درمیومد:

حالا بیا یه مثال کاربردی‌تر از تابع لامبدا بزنیم که در اون با دو تا آرگومان کار شده:

خروجی
9

معمولاً وقت‌هایی سراغ توابع لامبدا می‌ریم که صرفاً برای یه مدت خیلی کوتاه به یه تابع یک‌بارمصرف نیاز داریم و قراره فقط موقع اجرای برنامه همون‌جا ساخته بشه. یکی از رایج‌ترین جاهایی که توابع لامبدا خیلی به کار میان، استفاده در توابعی مثل filter()، map() و reduce() هست:

تابع filter() همون‌طور که از اسمش معلومه، میاد و مقادیر لیست my_list رو بر اساس شرطی که بهش دادی (مثلاً x > 10) فیلتر می‌کنه. از اون طرف، تابع map() یه فرمول خاص رو برای تک‌تک اعضای لیست my_list اعمال می‌کنه؛ در این مثال، همهٔ اعضا رو ضربدر 2 کرده.

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

استفاده از تابع ()main در پایتون

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

می‌تونی خیلی راحت یه تابع با نام main() بسازی و مثل بقیه توابع صداش بزنی:

در کدی که می‌بینی، اگه این فایل رو بخوای به عنوان یه ماژول در یه کد دیگه ایمپورت کنی، تابع main() بلافاصله اجرا می‌شه. برای جلوگیری از این اتفاق، اجرای main() رو داخل یه شرط __name__ == '__main__' قرار می‌دیم تا فقط در صورتی اجرا بشه که خود این فایل رو مستقیماً ران کنیم.

یعنی کدی که بالا نوشتیم به این شکل در میاد:

حواست باشه که در کنار __main__ ما یه تابع کاربردی به اسم __init__ هم داریم که نقش مقداردهی اولیه به یه کلاس یا شیء رو بر عهده داره. به زبان ساده، این متد مثل یه سازنده عمل می‌کنه و هر موقع نمونهٔ جدیدی از یه کلاس بسازی، خودبه‌خود اجرا می‌شه. همون‌طور که اوایل این آموزش گفتیم، شیء جدیدی که ساخته می‌شه مستقیماً به پارامتر self در متد __init__ اختصاص پیدا می‌کنه. به این مثال عالی توجه کن:

تمرین روی توابع پایتون رو ادامه بده

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

اشتراک‌گذاری
فهرست مطالب
  • توابع در پایتون
  • چطور یه تابع بسازیم؟ (توابع تعریف‌شده توسط کاربر)
  • توابع ناشناس در پایتون
  • استفاده از تابع ()main در پایتون
  • تمرین روی توابع پایتون رو ادامه بده

سوالات متداول

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

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

توابع مستقلن، ولی متدها متعلق به کلاس‌ها هستن. همهٔ متدها تابع به حساب میان، اما هر تابعی متد نیست.

در پایتون سه دسته تابع داریم: توابع داخلی (مثل print())، توابعی که کاربر تعریف می‌کنه (همون توابع سفارشی خودمون) و توابع ناشناس (مثل توابع موقت lambda).

پارامترها متغیرهایی هستن که موقع تعریف تابع می‌نویسیم، اما آرگومان‌ها اون مقادیر واقعی‌ای هستن که موقع فراخوانی تابع بهش پاس می‌دیم.

تابع لامبدا یه تابع یک‌خطی و بدون اسمه که برای انجام کارهای سریع استفاده می‌شه.

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

متغیرهای سراسری همه‌جا در دسترس هستن، ولی متغیرهای محلی فقط داخل همون تابعی که تعریف شدن شناخته می‌شن.

دریافت اپلیکیشن فینکا

با اپلیکیشن فینکا، به بیشتر دوره‌ها و مسیرها روی موبایل دسترسی دارید، تمرین می‌کنید و یادگیری رو هم‌زمان روی موبایل و دسکتاپ ادامه می‌دید.