آشنایی با نحوه ی تعریف و فراخوانی فانکشن های پارامتری در زبان برنامه نویسی پایتون

سیده آمین ارمان

کاربر نگاه دانلود
کاربر نگاه دانلود
عضویت
2016/05/10
ارسالی ها
1,730
امتیاز واکنش
20,744
امتیاز
795
محل سکونت
البرز
در آموزش قبل با نحوه ی تعریف و فراخوانی یک فانکشن به صورت ساده آشنا شدیم و دیدیم که چنین فانکشن هایی چگونه از تکرار کدها جلوگیری می کنند. همان طور که پیش از این گفتیم، فانکشن ها مانند یک دستگاه عمل می کنند، که گاهی برای راه اندازی این دستگاه ها لازم است به آن ها ورودی خاصی بدهیم (مثال دستگاه آبمیوه گیری را به خاطر آورید.) چنین فانکشن هایی علاوه بر آن که از تکرار کدها جلوگیری می کنند این انعطاف پذیری را نیز دارند که بر اساس ورودی ها یا آرگومان های مختلفی که به آن ها داده می شود خروجی های متفاوتی در اختیار ما قرار دهند. اگر بخواهیم درک بهتری از این نوع فانکشن ها داشته باشیم، می‌توانیم اصطلاحی همچون «فانکشن های پارامتری» را برای این چنین فانکشن هایی در نظر بگیریم. در این آموزش با نحوه ی تعریف و فراخوانی این فانکشن ها آشنا خواهیم شد.

فرض کنید بخواهیم فانکشنی را تعریف کنیم که در هر نوبت از فراخوانی، نام کاربر را به آن بدهیم تا یک پیغام خوشامدگویی را همراه با نام کاربر در خروجی چاپ کند. برای این کار برنامه ی زیر را در فایلی با نام greetUserFunc.py ذخیره کرده و اجرا می کنیم:

def greetUser(name):
print("Hello dear",name,",")
print("Welcome to SokanAcademy.com")
greetUser('Ali')
greetUser('Sara')
greetUser('Amir')
خروجی حاصل از این برنامه به صورت زیر است:

Hello dear Ali ,
Welcome to SokanAcademy.com
Hello dear Sara ,
Welcome to SokanAcademy.com
Hello dear Amir ,
Welcome to SokanAcademy.com
همان طور که در بخش هدر دستور تعریف فانکشن ()greetUser می بینید، در میان پرانتزها یک پارامتر با نام name قرار گرفته است. هر پارامتر متغیری است که در زمان فراخوانی فانکشن، آرگومانی که به آن فانکشن می دهیم به این متغیر یا پارامتر ارجاع داده می شود و در بدنه ی فانکشن مورد استفاده قرار می گیرد. در این برنامه سه بار فانکشن ()greetUser را به ترتیب با آرگومان های 'Sara'، 'Ali'، و 'Amir' فراخوانی کرده ایم. در هر نوبت پارامتر name به یکی از این آرگومان ها منتسب می شود، سپس در دستور ( ",",print("Hello dear",name از آن استفاده می شود.

نکته
همان طور که گفتیم، پارامترهای هر فانکشن یک متغیر هستند و مانند تمام متغیرها برای نام گذاری آن ها از شناسه های مجاز دلخواه استفاده می شود. بهتر است برای نام گذاری پارامترها از شناسه های با معنی استفاده کنیم که نشان دهنده ی ماهیت آرگومان های ارجاع داده شده به آن ها باشند. برای مثال در صورتی که یک فانکشن آرگومان هایی را به عنوان نام، رنگ، و شکل می گیرد به ترتیب از شناسه های color، name، و shape برای نام گذاری پارامترهای آن استفاده کنیم.
یک فانکشن می تواند به تعداد دلخواه و مورد نیاز پارامتر داشته باشد. در این صورت فرم کلی بخش هدر فانکشن به صورت زیر خواهد بود:

def functionName(par1,par2,par3,…,parN)
همان طور که می بینید، نام تمام پارامترها در بین پرانتزهای جلوی شناسه ی فانکشن قرار می گیرند و با علامت کاما از هم جدا می شوند. توجه داشته باشید که هر چند تعداد پارامترهای یک فانکشن دلخواه است، با این حال باز هم باید این موضوع را رعایت کنیم که این تعداد خیلی زیاد نباشد، چرا که تعداد زیاد پارامترها باعث پیچیدگی فانکشن خواهد شد. برای مثال فانکشن زیر را در نظر بگیرید:

def times(value1,value2):
print(value1*value2)
در این مثال فانکشن ()times دو پارامتر می گیرد. در زمان فراخوانی این فانکشن و هم چنین سایر فانکشن ها نکاتی را باید رعایت کنیم که در این جا به آن ها اشاره می کنیم:

1- در مورد فانکشن هایی مانند ()times که در تعریفشان حداقل یک پارمتر برای آن ها در نظر گرفته شده باشد، در صورتی که در زمان فراخوانی هیچ آرگومانی به آن ها ندهیم یا تعداد آرگومان هایی که به فانکشن می دهیم کم تر یا بیش تر از تعداد پارامترهای فانکشن باشد، مفسر پایتون اعلام خطا خواهد کرد. در تصویر زیر، نمونه هایی از این اشتباهات را در مورد فانکشن ()times می بینید:



همان طور که می بینید، تنها زمانی که فانکشن ()times به طور صحیح تعداد 2 آرگومان گرفته است -دستور آخر- به درستی اجرا می شود، و در بقیه ی موارد مفسر اعلام می کند که تعداد آرگومان ها متناسب با تعداد مورد انتظار نیست (البته توجه داشته باشید که اگر در زمان فراخوانی فانکشن های فاقد پارامتر هم به آن ها آرگومان بدهیم، با اعلام خطا از طرف مفسر مواجه خواهیم شد.)

پس به طور کلی در زمان فراخوانی فانکشن هایی که خودمان آن ها را تعریف کرده ایم به این نکته توجه می کنیم که تعداد آرگومان هایی که به فانکشن می دهیم برابر با تعداد پارامترهایی باشد که در زمان تعریف برای آن ها در نظر گرفته ایم. این موضوع که روی فانکشن هایی که خودمان تعریف کرده ایم تأکید داریم به این خاطر است که مثلاً در زمان فراخوانی فانکشن از پیش تعریف شده ی ()print می توانیم به آن به تعداد دلخواه آرگومان بدهیم یا اصلاً هیچ آرگومانی به آن ندهیم. اما در مورد فانکشن هایی که خودمان تعریف می کنیم مجاز به انجام چنین کاری نیستیم!

2- در فانکشن هایی مانند ()times که بیش از یک پارامتر می گیرند، دو روش برای ارجاع آرگومان ها به پارامترها وجود دارد:

در روش اول همان طور که دیدید، آرگومان ها را به ترتیب به فانکشن می دهیم و مانند پارامترها آن ها را هم با علامت , از هم جدا می کنیم. در این حالت مفسر پایتون از سمت چپ شروع می کند و آرگومان اول را به پارمتر اول، آرگومان دوم را به پارامتر دوم و و به همین ترتیب با پیش روی به سمت راست هر آرگومان را به پارامتر متناظر با آن ارجاع می دهد. برای مثال فانکشن ()addition را به صورت زیر در نظر بگیرید:

def addition(value1,value2):
print(value1,"+",value2,"=",value1+value2)
اجازه دهید این فانکشن را با آرگومان های 3 و 5 فراخوانی کنیم:

>>> addition(3,5)
3 + 5 = 8
همان طور که می بینید، به ترتیب آرگومان اول این فانکشن که مقدار آن 3 است به پارامتر اول یعنی value1 و آرگومان دوم با مقدار 5 به پارامتر دوم یعنی value2 ارجاع داده شده اند، سپس از آن ها در دستور پرینت در بدنه ی فانکشن استفاده شده است.

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

>>> addition(value2 = 5,value1 = 3)
3 + 5 = 8
همان طور که می بینید با وجود آن که ابتدا پارامتر دوم فانکشن مقدار دهی شده است سپس پارامتر اول، باز هم خروجی فانکشن مانند حالت قبل است.

سؤال: آیا می توانیم بعضی از آرگومان ها را با کیورد مقدار دهی کنیم و بعضی را نه؟ جواب این است که بله، اما در این صورت باید ترتیب را رعایت کنیم. برای مثال به جای دستور بالا می توانیم از دستور زیر استفاده کنیم:

>>> addition(3,value2 = 5)
3 + 5 = 8
اما اگر همین دستور را بدون رعایت ترتیب پارامترها وارد کنیم با خطا رو به رو می شویم:

>>> addition(value2 = 5,3)
SyntaxError: positional argument follows keyword argument
البته بهتر این است که از یک روش واحد برای آرگومان دهی به فانکشن ها استفاده کنیم، یعنی یا به صورت ترتیبی یا با استفاده از کیوردها این کار را انجام دهیم. از طرف دیگر اگر از کیوردها برای آرگومان دهی به فانکشن ها استفاده می کنیم، در صورتی که در تعریف فانکشن تغییری را در شناسه ی پارامترها ایجاد کردیم، باید در تمام دستورات فراخوانی فانکشن هم آن تغییرات را در کیوردها اعمال کنیم.

3- علاوه بر دو روش آرگومان دهی به فانکشن ها که در بالا به آن ها اشاره کردیم، روش سومی هم وجود دارد به این صورت که به صورت پیش فرض در دستور تعریف فانکشن به پارامترهای آن آبجکت هایی را منتسب می کنیم. برای مثال برنامه ای را که پیش از این فانکشن ()greetUser را در آن تعریف کرده بودیم به صورت زیر تغییر می دهیم:

def greetUser1(name="User"):
print("Hello dear",name,",")
print("Welcome to SokanAcademy.com")
greetUser1()
greetUser1("Reza")
اسکریپت این برنامه را در فایل greetUser1.py ذخیره کرده و آن را اجرا می کنیم. خروجی حاصل از اجرای این برنامه به صورت زیر است:

Hello dear User ,
Welcome to SokanAcademy.com
Hello dear Reza ,
Welcome to SokanAcademy.com
همان طور که در کدهای برنامه می بینید، با وجود آن که در تعریف فانکشن ()greetUser1 پارامتری با شناسه ی name برای آن در نظر گرفته شده است، اما در اولین فراخوانی این فانکشن هیچ آرگومانی به آن نداده ایم. قبلاً گفتیم که در چنین مواقعی مفسر پایتون اعلام خطا خواهد کرد، اما در این جا چون به صورت پیش فرض در دستور تعریف فانکشن استرینگ "User" را به پارامتر name منتسب کرده ایم، مفسر از همان مقدار پیش فرض استفاده کرده و برنامه را به درستی اجرا می کند. همان طور که می بینید در فراخوانی این فانکشن برای بار دوم، زمانی که استرینگ "Reza" را به عنوان آرگومان به آن داده ایم، این مقدار جایگزین مقدار پیش فرض شده و در بدنه ی فانکشن مورد استفاده قرار گرفته است.

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

برای مثال یک بار دیگر به تعریف فانکشن ()times باز گردیم. این فانکشن دو آرگومان را به عنوان ورودی می گیرد و عملگر * را روی آن ها اثر داده و آن گاه خروجی را در صفحه چاپ می کند. فراخوانی این تابع را در دستورات زیر در نظر بگیرید و به نوع آرگومان ها و خروجی آن ها توجه کنید:

>>> times(10,9)
90
>>> times('***',3)
*********
همان طور که می بینید، در دستور اول آرگومان های فانکشن ()times هر دو از نوع عدد صحیح هستند، اما در دستور فراخوانی دوم آرگومان اول از نوع استرینگ و آرگومان دوم از نوع int است. از آن جا که عملگر * در هر دو مورد عمل می کند این دستورات اجرا می شوند، با این حال باید به این موضوع توجه داشته باشیم که ممکن است گاهی آرگومان هایی به فانکشن داده شود که باعث بروز خطا در برنامه شوند. برای مثال تابع ()addition که پیش از این تعریف کردیم را در نظر بگیرید. مثال هایی از دستورات فراخوانی این فانکشن در زیر آمده است:

>>> addition(10,20)
10 + 20 = 30
>>> addition('Sokan','Academy')
Sokan + Academy = SokanAcademy
>>> addition('Sokan',20)
Traceback (most recent call last):
File "<pyshell#36>", line 1, in
addition('Sokan',20)
File "<pyshell#32>", line 2, in addition
print(value1,"+",value2,"=",value1+value2)
TypeError: Can't convert 'int' object to str implicitly
همان طور که می بینید در دو دستور فراخوانی اول و دوم آرگومان هایی از نوع int و استرینگ استفاده شده اند، اما وقتی در دستور فراخوانی سوم از آرگومان هایی با نوع متفاوت استفاده می کنیم -یک استرینگ و یک عدد صحیح- برنامه با خطا رو به رو می شود چرا که در دستور value1+value2 نمی توانیم یک استرینگ را با یک عدد صحیح جمع بزنیم و این عملیات تعریف نشده است. پس به طور کلی باید به این موضوع توجه داشته باشیم که مفسر پایتون به هیچ عنوان بررسی نمی کند که آیا نوع آرگومانی که به فانکشن می دهیم مناسب است یا نه. در مورد شیوه های کنترل و جلوگیری از چنین خطاهایی در فصول آینده صحبت خواهیم کرد.
 

برخی موضوعات مشابه

بالا