در این قسمت از دوره آموزش پایتون فنولوژی، در مورد تابع در پایتون صحبت میکنیم. در این بخش انواع توابع، آرگومانهای ورودی، نحوه تعریف و فراخوانی توابع پایتون را به همراه مثالهای کاربردی به صورت کامل توضیح خواهیم داد. با ما همراه باشید.
تابع در پایتون چیست؟
تابع در پایتون مانند سایر زبانهای برنامه نویسی، یک قطعه کد است که تنها در صورتی که آن را فراخوانی کنیم اجرا میشود. هدف از استفاده از توابع، بهینهسازی برنامه نویسی است تا مجبور نباشیم آن قطعه کد را هر بار مجددا کپی کنیم؛ بلکه تنها یک بار آن را تعریف کنیم و هر موقع به آن نیاز داشتیم، اقدام به فراخوانی تابع کنیم. تابع در پایتون شامل دو مرحلهی تعریف، و فراخوانی است و همچنین شامل تعدادی پارامتر ورودی و یک مقدار خروجی به عنوان نتیجهی تابع است. (البته ممکن است خروجی چیزی بر نگرداند که در ادامه توضیح میدهیم.)
انواع تابع در پایتون
به طور کلی میتوان انواع تابع در پایتون را به سه دسته زیر تقسیم بندی نمود:
- توابع داخلی یا پیش فرض: مانند تابع help برای مطالعه دستورالعملهای توابع، min برای دریافت حداقل مقدار و یا print برای چاپ یک شی در ترمینال. شما میتوانید یک نمای کلی از بیشتر این توابع را در اینجا پیدا کنید.
- توابع تعریف شده توسط کاربر (UDF): توابعی که کاربران برای استفاده در کدهای خود ایجاد میکنند و موضوع بحث این مقاله است.
- توابع ناشناس: که به آنها توابع lambda نیز گفته میشود زیرا با کلمه کلیدی def استاندارد اعلام نشدهاند.
تفاوت پارامتر و آرگومان تابع در پایتون
عبارات پارامتر (parameters) و آرگومان (argument) ممکن است در مواردی به اشتباه به جای هم استفاده شود. اما تفاوتها و شباهتهای آنها چیست؟ هر دوی آنها برای دادههایی که به تابع ورودی داده میشوند استفاده میشود اما تفاوتهای زیر را دارند:
- پارامتر، متغیری است که در تعریف تابع در داخل پرانتز ورودی میدهیم.
- آرگومان، مقادیر پارامترهاست که در فراخوانی تابع در داخل پرانتز ورودی داده میشود.
میتوان یک یا چند آرگومان ورودی به تابع داد که در ادامه در مورد انواع آنها صحبت میکنیم. آرگومانها را در پایتون با علامت کاما جدا میکنند. به مثال زیر توجه کنید. fname یک پارامتر است که هنگام تعریف داده استفاده شده است و «Emil» و … آرگومانهایی هستند که هنگام فراخوانی تابع به عنوان مقدار آن پارامتر مورد استفاده قرار میگیرند.
1 2 3 4 5 6 |
def my_function(fname): print(fname + " Refsnes") my_function("Emil") my_function("Tobias") my_function("Linus") |
تعریف تابع
برای تعریف تابع در پایتون مراحل زیر را دنبال کنید:
- تعریف: با استفاده از دستور def تابع را تعریف کنید و اسم تابع را رو بروی این دستور بنویسید. (توجه کنید اسمی که انتخاب میکنید با توابع پیش فرض پایتون یکی نباشد.)
- افزودن پارامترها به تابع: این پارامترها داخل پرانتر روبروی اسم تابع وارد میشوند. سپس از دو نقطه پس از پرانتز استفاده میکنیم.
- دستورات داخل تابع: قطعه کدی که میخواهید تابع انجام دهد را وارد کنید.
- با استفاده از دستور return خروجی مد نظر را برگردانید. اگر از این دستور استفاده نکنید، به طور پیش فرض مقدار None برگردانده میشود.
- محتوای داخل تابع را با تورفتگی (Indent) باید متمایز کنید.
مثال:
1 2 |
def my_function(): print("Hello from a function") |
فراخوانی تابع
برای فراخوانی تابع از اسم تابع به همراه آرگومانهایی که میخواهیم داخل پرانتز استفاده میکنیم. تابعی که در مثال قبل ساختیم را اکنون فراخوانی میکنیم:
1 2 3 4 |
def my_function(): print("Hello from a function") my_function() |
با فراخوانی این تابع (که آرگومان ورودی و عبارت خروجی ندارد)، عبارت داخل print نمایش داده میشود.
انواع آرگومان توابع
انواع آرگومانهای تابع در پایتون را میتوان از جنبههای گوناگون دسته بندی کرد که در ادامه به طور مجزا در مورد هریک صحبت میکنیم. (توجه کنید ممکن است این دستهبندیها با یکدیگر همپوشانی داشته باشند.)
از نظر الزام ورودی دادن:
- پیش فرض (Default)
- مورد نیاز (Required)
از نظر نوع آرگومان:
- آرگومان معمولی (Argument)
- آرگومان با کلمه کلیدی (Keyword Agument)
- آرگومان لیست در پایتون
از نظر تعداد پارامترهای ورودی:
- مشخص
- نامشخص (args* و kwargs**)
آرگومان default
این آرگومانها، در هنگام تعریف تابع مقدار دهی میشوند؛ به همین دلیل هنگام فراخوانی تابع دیگر لزومی به مقدار دهی آنها نیست و اگر در فراخوانی مقداردهی نکنید، بدون خطا دادن تابع اجرا میشود و همان مقداری که در زمان تعریف، مقدار دهی شده بود در نظر گرفته میشود.
در هنگام تعریف تابع با علامت «=» میتوان یک پارامتر را به عنوان پارامتر پیشفرض تنظیم کرد. در مثال زیر، متغیر a، یک آرگومان مورد نیاز (required) و متغیر b یک آرگومان پیشفرض است که اگر آن را به عنوان ورودی تابع قرار ندهیم، به صورت پیشفرض برابر ۲ خواهد بود. اما اگر آن را تغییر دهیم، مقدار جدید را به خود میگیرد.
1 2 3 4 5 6 |
def plus(a,b = 2): return a + b plus(1) plus(1, 3) |
خروجی:
1 2 |
3 4 |
آرگومان required
اگر مقدار پیشفرض برای پارامترهای تابع تعریف نکنیم، از جنس مورد نیاز یا required خواهند بود. در این صورت باید حتما ترتیب و تعداد ورودیها را رعایت کنید و دقیقا به همان صورت که در هنگام تعریف پارامترها داشتیم، در مقدار دهی آرگومانها نیز به همان صورت مقدار دهی کنیم تا تابع بدون خطا و به درستی اجرا شود.
به مثال زیر توجه کنید. متغییرهای a و b هر دو آگومانهای مورد نیاز هستند که باید هر دو به ترتیب هنگام فراخوانی تابع ورودی داده شوند.
1 2 3 4 |
def divide(a,b): return a/b divide(6,3) |
خروجی:
1 |
2 |
آرگومان معمولی (مخفف args)
تفاوت این نوع، با انواع دیگر این است که در دادن آرگومان هنگام فراخوانی تابع، ترتیب اهمیت دارد. به مثال زیر توجه کنید. در این مثال باید حتما ترتیب وارد کردن اسامی هنگام فراخوانی رعایت شود.
1 2 3 4 |
def my_function(child3, child2, child1): print("The youngest child is " + child3) my_function("Linus","Tobias","Emil") |
خروجی:
1 |
The youngest child is Linus |
آرگومان کیورد (مخفف kwargs)
در این حالت میتوانید با سینتکس key=value آرگومانهای ورودی را به تابع بدهید. در این صورت میتوانید ترتیب استفاده از آرگومانها را خودتان تعیین کنید. به مثال زیر توجه کنید. در این مثال به ترتیب متفاوتی توانستیم همان متغیرها را به تابع ورودی دهیم.
1 2 3 4 |
def my_function(child3, child2, child1): print("The youngest child is " + child3) my_function(child1 = "Emil", child2 = "Tobias", child3 = "Linus") |
خروجی:
1 |
The youngest child is Linus |
آرگومان به صورت لیست
شما میتواند انواع دیتا تایپ در پایتون را به عنوان ورودی تابع بدهید و در داخل تابع نیز با همان نوع داده شناخته میشود. به عنوان یک مثال کاربردی میتوانید ورودی یک تابع را به عنوان لیست وارد کنید. در این صورت باید داخل تابع نیز حواستان باشد مثل یک لیست با آن پارامتر برخورد کنید.
به مثال زیر توجه کنید.
1 2 3 4 5 6 7 |
def my_function(food): for x in food: print(x) fruits = ["apple", "banana", "cherry"] my_function(fruits) |
خروجی:
1 2 3 |
apple banana cherry |
آرگومان با تعداد ورودی مشخص
در حالت عادی تعداد آرگومانهای ورودی هنگام فراخوانی تابع، باید دقیقا برابر تعداد پارامترهای تابع هنگام تعریف باشد. به مثال زیر دقت کنید. این تابع دقیقا ۲ پارامتر دارد و هنگام فراخوانی نیز دقیقا ۲ آرگومان به آن داده شده است. اگر تعداد آرگومانها مشخص نباشد در ادامه توضیح میدهیم چگونه باید این مشکل را حل نمود.
1 2 3 4 |
def my_function(fname, lname): print(fname + " " + lname) my_function("Emil", "Refsnes") |
اگر تعداد آرگومانها ۱ یا ۳ تا باشد برنامه با خطا مواجه خواهد شد. مانند برنامهی زیر که خطا خواهد داد!
1 2 3 4 |
def my_function(fname, lname): print(fname + " " + lname) my_function("Emil") |
آرگومان با تعداد ورودی نامشخص
اگر تعداد ورودیهای تابع نامشخص باشد، میتوانیم از عبارات args* یا kwargs** استفاده کنیم. تفاوت آنها در این است که از آرگومان معمولی یا آرگومان کیورد(key=value بدون اهمیت ترتیب) بهره ببریم.
- آرگومانهای نامشخص args*:
اگر بخواهیم از آرگومان معمولی استفاده کنیم (بدون key=value و ترتیب مهم باشد)، با عبارت args* میتوانیم تابع را تعریف کنیم و در فراخوانی هر تعداد ورودی که بدهیم در یک متغیر تاپل در پایتون با نام args ذخیره میشود. (به جای کلمهی args میتوان از هر اسم مجاز دیگری استفاده کرد.) به مثال زیر توجه کنیدک
1 2 3 4 |
def my_function(*kids): print("The youngest child is " + kids[2]) my_function("Emil", "Tobias", "Linus") |
خروجی:
1 |
Linus |
- آرگومانهای نامشخص kwargs**:
اگر بخواهیم با ترتیب دلخواه، با سینتکس key=value، و با تعداد نامشخص ورودی به تابع بدهیم، در تعریف تابع از عبارت kwargs** استفاده میکنیم. در این صورت مقادیر ورودی به صورت یک دیکشنری در پایتون به اسم kwargs ایجاد میشود. (به جای کلمهی kwargs میتوان از هر اسم مجاز دیگری استفاده کرد.) به مثال زیر توجه کنید.
1 2 3 4 |
def my_function(**kid): print("His last name is " + kid["lname"]) my_function(fname = "Tobias", lname = "Refsnes") |
خروجی:
1 |
His last name is Refsnes |
خروجی تابع با return در پایتون
همانطور که در طول مقاله مشاهده کردید، میتوانید تابع را بدون این که خروجی داشته باشد فراخوانی کنید. مثلا یک عبارت را چاپ کنید. اما اگر بخواهید خروجی (به جای None) توسط شما مشخص شود، از عبارت return استفاده کنید. هر دیتا تایپی که برگردانید، به همان صورت در کد اصلی استفاده میشود. مثال:
1 2 3 4 5 6 |
def my_function(x): return 5 * x print(my_function(3)) print(my_function(5)) print(my_function(9)) |
pass برای تابع در پایتون
در حالت عادی، توابع در هنگام تعریف نمیتوانند خالی باشند. اما اگر مجبور به انجام این کار شدید، برای جلوگیری از خطا میتوانید دستور pass استفاده کنید.
1 2 |
def myfunction(): pass |
توابع بازگشتی در پایتون
توابع بازگشتی، به شما این امکان را میدهند که در داخل یک تابع، خود آن تابع را فراخوانی کنید. در این صورت میتوانید نوعی حلقه در پایتون ایجاد کنید و تا رسیدن به یک نتیجهی خاص در آن حلقه بمانید. توجه کنید استفاده از این قابلیت نیاز به مهارت بالای برنامه نویس دارد وگرنه باعث میشود برنامه هیچ موقع از حالت اجرا خارج نشود و یا غیر بهینه حافظه و توان محاسباتی زیادی مصرف کند.
به مثال زیر توجه کنید:
1 2 3 4 5 6 7 8 9 10 |
def tri_recursion(k): if(k > 0): result = k + tri_recursion(k - 1) print(result) else: result = 0 return result print("\n\nRecursion Example Results") tri_recursion(6) |
خروجی:
1 2 3 4 5 6 7 |
Recursion Example Results 1 3 6 10 15 21 |
شاید در اوایل کار فهمیدن کار با این تابع مشکل به نظر برسد. برای انجام این کار باید مرحله به مرحله فرابندی که در تابع اتفاق میافتد را بنویسید تا متوجه شوید. در مثال بالا ابتدا بررسی میکند که عدد ۶ مثبت است. سپس در result به دنبال «۶+خروجی تابع به ازای ۵» میگردد. از آنجا که تا وقتی ورودی تابع ۰ نشود، باز خود را فراخوانی میکند، هر موقع به صفر رسیدیم، مرحله به مرحله خروجی قبلی را با اعداد ۱ تا ۶ جمع میکند و نمایش میدهد!
تفاوت متد و تابع
متد، به تابعی گفته میشود که به یک کلاس در پایتون تعلق دارد. برای درک تفاوت آنها باید مفاهیم شیئ گرایی را بدانید. به مثال زیر توجه کنید که تابع sum یک متد از کلاس summation است اما تابع plus، متد نیست.
1 2 3 4 5 6 7 8 9 |
# Define a function `plus()` def plus(a,b): return a + b # Create a `Summation` class class Summation(object): def sum(self, a, b): self.contents = a + b return self.contents |
افزودن Docstring به تابع در پایتون
Docstring یا توضیحات تابع، میتواند در راهنمایی کاربران شما و کسانی که از کدهای شما استفاده میکنند بسیار مفید باشد. داکسترینگ میتواند پارامترها، محاسبات و یا خروجیهای تابع شما را توضیح دهد. برای این کار باید بلافاصله پس از تعریف تابع، توضیحات مد نظر را بین دو عبارت «”””» قرار دهیم.
1 2 3 4 5 6 7 8 9 10 |
def hello(): """Prints "Hello World" Returns: None """ print("Hello World") help(hello) |
خروجی:
1 2 3 4 |
Prints "Hello World" Returns: None |
help توابع در پایتون
همانطور که در پاراگراف قبلی آموختیم برای توابع توضیحات یا documentation string بسازیم، برای فراخوانی آن از دستور help(FunctionName) استفاده میکنیم. برای درک توابع پیچیدهای که در فریمورکها استفاده میشود، این دستور بسیار مفید است.
متغیرهای سراسری و محلی
متغیرهای محلی در داخل توابع ایجاد میشوند و تنها از داخل تابع قابل دسترسی هستند و متغیرهای سراسری خارج از توابع تعریف میشوند و همه جا از جمله داخل توابع نیز قابل دسترسی هستند.
به مثال زیر توجه کنید. متغیر out سراسری است و داخل تابع از آن استفاده شده است. اما متغیر init داخلی است و اگر خط آخر را از حالت کامنت خارج کنید برنامه با خطا مواجه خواهد شد!
1 2 3 4 5 6 7 8 9 |
out = 1 def plus(): init = 1 return init+out print("this is the initialized value " + str(out)) print("total plus init is: " + str(plus())) #print("this is the sum " + str(init)) |
1 2 |
this is the initialized value 1 total plus init is: 2 |