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


در آموزش های گذشته با مفهوم فانکشن ها یا توابع آشنا شدیم و دانستیم که در زبان پایتون فانکشن ها، آبجکت های نمونه ای از کلاس function زبان برنامه نویسی Python هستند که هر کدام از آن ها مانند دستگاهی عمل می کند که می توانیم مجموعه ای از دستورالعمل ها را برای آن تعریف کرده و در هر زمان و هر جا که لازم بود دکمه ی استارت آن را بزنیم تا دستگاه روشن شود و تمام آن کارها را به یکباره انجام دهد! در حقیقت زمانی که نیاز داریم تا از یک بلوک کد چندین بار استفاده کنیم می توانیم آن بلوک را به یک فانکشن منتسب کنیم و با فراخوانی فانکشن تمام دستورات آن بلوک را اجرا کنیم، بدون آن که نیاز به تکرار و دوباره نویسی کدها داشته باشیم.

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

در زبان برنامه نویسی پایتون به منظور تعریف یک فانکشن برای مفسر از یک دستور مرکب استفاده می کنیم. در آموزش های قبل گفتیم که هر دستور مرکب با یک کلمه ی کلیدی آغاز می شود.

به خاطر داشته باشید
به یاد داشته باشیم که: در پایتون از کلمه ی کلیدی def برای تعریف یک فانکشن استفاده می کنیم. بدون شک، def از ابتدای فعل define به معنی «تعریف کردن» گرفته شده است.

فرم ساده ی هدر دستور مرکب تعریف فانکشن به صورت زیر است:

def function_name ():

بر اساس کد نوشته شده، واضح است که دستور تعریف فانکشن با کلمه ی کلیدی def آغاز شده است و در ادامه نام فانکشن و پس از آن پرانتزهای باز و بسته و در انتها مانند بخش هدر در تمام بندهای یک دستورِ مرکب، کاراکتر : قرار می گیرد.

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

نام فانکشن یک شناسه دلخواه است و برای انتخاب آن باید تمام قواعد مربوط به انتخاب شناسه ها در زبان پایتون را رعایت کنیم. جهت مرور قواعد می توانید به آموزش آشنایی با مفهوم متغیر در زبان برنامه نویسی پایتون مراجعه کنید.

بر اساس استانداردهای زبان پایتون، شناسه ی مناسب برای نام گذاری فانکشن ها بهتر است به دو صورت انتخاب شود. در شیوه ی اول تنها از کاراکترهایی با حروف کوچک انگلیسی استفاده می شود که در صورت انتخاب نام چند بخشی کاراکترهای هر کلمه با Underscore یا علامت (_) از هم جدا می شوند، یعنی نام فانکشن فرمی به صورت function_name دارد. درحالت دوم هم کافی است تا تمام کاراکترها از بین حروف کوچک انگلیسی انتخاب شوند و تنها در صورتی که بخواهیم از نامی چند بخشی استفاده کنیم حرف نخست هر کلمه به غیر از کلمه ی اول باید از میان حروف بزرگ انتخاب شود، به طور مثال شناسه ی functionName به عنوان نام یک فانکشن چنین فرمی دارد . (لازم به ذکر است که این سبک نامگذاری در برنامه نویسی را اصطلاحاً camelCase می‌گویند چرا که شکل شماتیک نام فانکشن همچون کوهان شتر است!) همان طورکه پیش از این نیز گفتیم هیچ اجباری برای رعایت این استانداردها وجود ندارد، با این حال پیروی از آن ها باعث می شود خوانایی برنامه های ما بیش تر شود و توسعه دهندگان دیگر بتوانند به راحتی منظور کدهای ما را درک کنند.

نکته
استفاده از شناسه های با معنی به عنوان نام فانکشن ها سبب افزایش خوانایی برنامه ها می شود. توصیه می کنیم شناسه های انتخابی به عنوان نام فانکشن ها با یک فعل شروع شوند. به طور کلی، منظور از یک فعل، کاری است که توسط یک فاعل صورت می گیرد. مثلاً فعل دویدن که توسط یک ورزشکار صورت می گیرد. با توجه به این که در برنامه نویسی نیز وظیفه ی هر فانکشن به انجام رساندن یک کار است، بهتر آن است که نام انتخابی برای یک فانکشن بیان گر کاری باشد که آن فانکشن انجام می دهد. مثلاً اگر فانکشنی داریم که قرار است هزینه ی سبد خرید یک فروشگاه آنلاین را محاسبه کند، نامی هم چون calculateCart می‌تواند مناسب باشد که از یک فعل -calculate به معنی محاسبه کردن- و یک نام -cart به معنی سبد خرید- در ساخت آن استفاده شده است. یا فرضاً اگر وظیفه ی فانکشنی که در برنامه ی خود تعریف می کنیم این باشد که یک شیء گرافیکی را در صفحه حرکت دهد، می توانیم از شناسه ی move به معنی "حرکت دادن" برای نام گذاری آن فانکشن استفاده کنیم.

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

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

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

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

در دوره ی آموزش زبان برنامه نویسی پایتون در سکان آکادمی، برای نوشتن بخش بدنه ی بندهای دستورات مرکب از روش دوم آن استفاده می کنیم. برای مثال برنامه ی زیر را که در آن فانکشنی به نام greet به معنی «سلام کردن» را تعریف و فراخوانی کرده ایم در نظر بگیرید:

def greet():
    print("Hello,")
    print("Welcome to SokanAcademy.com")
greet()
greet()
greet()

کدهای مربوط به این برنامه ی کوچک را در فایلی تحت عنوان greetFunc.py ذخیره می کنیم. در این برنامه می خواهیم از فانکشن greet برای خوشامدگویی به کاربران سکان آکادمی استفاده کنیم. همان طور که می بینید، دستورات مربوط به بدنه ی این فانکشن را در یک بلوک مجزا که دارای تورفتگی نسبت به بلوک اصلی برنامه است نوشته ایم. بعد از تمام شدن دستورات بدنه ی این فانکشن، مجدداً به بلوک اصلی برنامه برگشته ایم و خطوط دیگر کدهای این برنامه که دستور فراخوانی فانکشن greet هستند را بدون ایجاد تورفتگی سه بار پشت سر هم نوشته ایم.

پیش از این نیز با نحوه ی فراخوانی فانکشن های از پیش ساخته شده مانند ()help یا ()print آشنا شده بودیم. در حقیقت برای فراخوانی یک فانکشن کافی است نام آن را بنویسیم و پرانتزهای باز و بسته را در جلوی آن قرار دهیم. قرار دادن این پرانتزها به مفسر پایتون اعلام می کند که به فانکشنی با نام ذکر شده مراجعه کرده و دستورات بدنه ی آن را اجرا کند. خروجی حاصل از اجرای کدهای بالا به صورت زیر است:

Hello,
Welcome to SokanAcademy.com
Hello,
Welcome to SokanAcademy.com
Hello,
Welcome to SokanAcademy.com

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

def greet():
	print("Hello,")
print("Welcome to SokanAcademy.com")
greet()
greet()
greet()

خروجی حاصل از اجرای برنامه به صورت زیر خواهد بود:

Welcome to SokanAcademy.com
Hello,
Hello,
Hello,

همان طور که می بینید مفسر به ترتیب شروع به اجرای دستورات برنامه می کند. ابتدا با رسیدن به دستور def فانکشنی با نام greet می سازد. سپس دستور پرینت دوم را که دیگر در بدنه ی فانکشن قرار ندارد تنها یک بار اجرا می کند، آن گاه به سراغ دستورات فراخوانی فانکشن که در ادامه آمده اند می رود و چون تنها یک دستور پرینت در بدنه ی فانکشن قرار دارد، آن را سه بار اجرا می کند. بنابراین با توجه به این مثال در زمان تعریف فانکشن ها توجه داشته باشید که تمام دستورات لازم را با رعایت تورفتگی در بدنه ی تابع قرار دهید.

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

همان طور که گفتیم بهترین راه برای بررسی این موضوع این است که شما بتوانید کاری که هر فانکشن انجام می دهد را در قالب یک فعل بیان کنید و آن را به عنوان شناسه ی فانکشن قرار دهید. برای مثال فانکشنی که ما در این مثال تعریف کردیم برای بیان خوشامدگویی به کاربران است و نام آن را greet گذاشتیم؛ البته انتخاب نام و تعریف یک تابع همیشه به این سادگی نیست و نیاز به تمرین و توجه دارد.

همان طور که گفتیم هر فانکشن در پایتون یک آبجکت است که در زمان تعریف آن با استفاده از کلمه ی کلیدی def یک شناسه که همان نام تابع است را به آن منتسب می کنیم. در حقیقت این شناسه مانند نام یک متغیر است و کلمه ی کلیدی def نیز در این جا مانند عملگر = برای انتساب فانکشن به این متغیر عمل می کند؛ بنابراین می توان هر متغیر دیگری را نیز به یک فانکشن منتسب کرد. برای مثال، فرض کنید بخواهیم در برنامه ی greetFunc.py متغیر دیگری به نام welcome را به فانکشنی که با نام greet تعریف شده است منتسب کنیم. برای این کار از دستور زیر استفاده می کنیم:

welcome = greet

دقت کنید که در این دستورات تنها از نام متغیرها استفاده شده است و علامت پرانتزها که برای اجرای فانکشن به کار می رود را از آن ها حذف کرده ایم. اکنون متغیر welcome به یک آبجکت از نوع فانکشن منتسب شده است و می توانیم آن را با این نام جدید فراخوانی کنیم:

>>> welcome()
Hello,
Welcome to SokanAcademy.com

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

>>> write = print
>>> write("This is a new name for print function.")
This is a new name for print function.

بنابراین اهمیتی ندارد که شما با چه نامی یک فانکشن را فراخوانی می کنید، مهم این است که قبلاً آن نام را به فانکشن مورد نظر خود منتسب کرده باشید.

دانلود فایل‌های تمرین
لیست نظرات
کاربر میهمان
دیدگاه شما چیست؟
کاربر میهمان
orkobon
orkobon
سلام
def greet():
print("Hello,")
print("Welcome to SokanAcademy.com")
greet()
greet()
greet()
در قسمت ( "print("Welcome to SokanAcademy.com ارور میده شاید چیزی باید به اخرش اضافه کنم .
لطفا راهنمایی بفرمائید
کاربر میهمان
aminمن یک کاربر مهمان هستم
خیلی خوب و کامل
Mostafa84
Mostafa84
خیلی ممنون از آموزش های خوبتون
Shayan
Shayan
با سلام.میخواستم بپرسم در مثال اول چطور به بلوک اصلی برمیگردیم و greet رو سه بار مینویسیم
hacker
hacker
خسته نباشین وممنون بابت اموزش هاتونو ببخشید سوالی داشتم در این بخش (هِدِر)یعنی چی من نفهمیدم ممنون