داریوش مهدی پور یقینی
داریوش مهدی پور یقینی
خواندن ۷ دقیقه·۲ سال پیش

فصل چهاردهم آموزش پایتون مقدماتی - توابع

سلام دوستان

با ادامه ی کتاب پایتون مقدماتی که به همراه دوست عزیزم جناب مهندس مهدی عباسپور شاهمرس نوشته و چاپ کردیم در خدمتتون هستیم.

https://virgool.io/@mahdi.abbaspour.sh

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

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

[1]User-defined Functions

14-1- تعریف تابع

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

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

شمای کلی تعریف یک تابع را در شکل (14-1) مشاهده می‌‌کنید.

شکل (14-1)
شکل (14-1)

لازم به ذکر است که، به طور پیش فرض، رفتار پارامترها برحسب مکان آن‌‌ها، متغییر است. شما بایستی از آن‌‌ها به همان ترتیبی که نوشته‌‌اید، استفاده کنید. این امر بیشتر در صدا زدن توابع، کاربرد دارد. برای درک بهتر مطلب، در شکل (14-2)، تابع ما، یک رشته را به عنوان پارامتر ورودی گرفته و آن را چاپ می‌‌کند.

شکل (14-2)
شکل (14-2)

14-2- فراخوانی تابع

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

شکل (14-3)
شکل (14-3)

با توجه به مقدار بازگشتی تابع printme، خروجی ما به شکل (14-4) خواهدبود.

شکل (14-4)
شکل (14-4)

14-3- ارسال پارامتر با مقدار و ارسال با مرجع[1]

در زبان پایتون، تمام پارامترها (آرگومان‌‌ها)، توسط مرجع ارسال می‌‌شوند. به عبارت دیگر، اگر در چیزی که یک پارامتر به درون تابع ارجاع می‌‌دهد، تغییری ایجاد‌‌کنیم، این تغییر در مقادیر فراخوانی‌‌کننده نیز تاثیر دارد. این مطلب را در مثال شکل (14-5) نشان‌‌دادیم.

شکل (14-5)
شکل (14-5)

همان طوری که در شکل (14-6) می‌‌بینید، ابتدا، لیست myList به تابع ارسال‌‌شده و در داخل تابع، مقادیری به آن افزوده‌‌شده و در نهایت چاپ می‌‌شود. این تغییر لیست، به دستور چاپِ خارج از تابع نیز اعمال می‌‌گردد. در نتیجه هر دو دستور چاپ، مقادیر یکسانی را در خروجی تولید می‌‌کنند.

شکل (14-6)
شکل (14-6)

شکل (14-7)، مثال دیگری را به نمایش می‌‌گذارد که در آن آرگومان‌‌ها به صورت ارجاعی، فرستاده‌‌شده و این ارجاع در داخل تابع، بازنویسی می‌‌شود.

شکل (14-7)
شکل (14-7)

در این مثال، پارامتر mylist به صورت محلی در تابع changeme تعریف شده‌‌است. در نتیجه، تغییر در لیست داخل تابع، در لیست اصلی تاثیری نمی‌‌گذارد. در نهایت، خروجی ما به شکل (14-8) می‌‌شود. سطر اول خروجی، نتیجه‌‌ی اجرای تابع و سطر دوم نتیجه‌‌ی دستور چاپ خارج از تابع است.

شکل (14-8)
شکل (14-8)
[1]Pass by reference vs value

14-4- آرگومان‌‌های تابع

شما می‌‌توانید یک تابع را با استفاده از این چهار نوع آرگومان رسمی، فرخوانی‌‌کنید:

14-4-1- آرگومان‌‌های ضروری

همان طوری که از نامش پیداست، برای این که توابع ما، به صورت صحیح و بدون خطا کار‌‌کنند، باید این آرگومان‌‌ها ارسال‌‌شوند. البته تعداد و ترتیب آن‌‌ها در زمان ارسال بایستی با تعداد و ترتیب پارامترهای تعریف‌‌شده در تابع، مطابقت داشته‌‌باشد. در شکل (14-9)، ما هیچ آرگومانی را برای تابع printme ارسال‌‌نکردیم.

شکل (14-9)
شکل (14-9)

خروجی این مثال را در شکل (14-10) می‌‌بینید. به دلیل عدم ارسال این پارامتر ضروری، با یک خطای نحوی روبرو می‌‌شویم.

شکل (14-10)
شکل (14-10)

14-4-2- آرگومان‌‌های کلمه‌‌کلیدی

این آرگومان‌‌ها، در زمان فراخوانی توابع، تعریف و مقداردهی می‌‌شوند. زمان استفاده از آن‌‌ها، هر آرگومانی، با نام خودش، شناسایی می‌‌شود. این کار به ما اجازه می‌‌دهد تا تعدادی از آرگومان‌‌ها را حذف‌‌کرده ویا آن‌‌ها را خارج از ترتیب وارد‌‌کنیم. مترجم پایتون قادر است برای تطبیق مقادیر پارامترها از کلمات‌‌کلیدی ارائه‌‌شده استفاده‌‌نماید. به عنوان مثال، می‌‌توان تابع printme را به صورت شکل (14-11) فراخوانی‌‌نمود.

شکل (14-11)
شکل (14-11)

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

شکل (14-12)
شکل (14-12)

14-4-3- آرگومان پیش‌‌فرض

اگر هیچ مقداری برای این نوع آرگومان‌‌ها اختصاص‌‌ندهیم، تابع مدنظر، از مقادیر پیش فرض استفاده می‌‌کند. با نگاه‌‌کردن به مثال شکل (14-13) درمی‌‌یابیم که بعد از تعریف تابع، یک بار آن را با مقداردهی همه‌‌ی پارامترها، فراخوانی‌‌کرده و بار دیگر تنها با مقداردهی یکی از آن‌‌ها، اقدام به فراخوانی‌‌کردیم.

شکل (14-13)
شکل (14-13)

بنابراین به دلیل عدم ارسال آرگومان age در فراخوانی تابع، برای دستور چاپ‌‌دوم، از مقدار پیش فرض آن، یعنی 33 استفاده می‌‌شود. خروجی این مثال به شکل (14-14) خواهدبود.

شکل (14-14)
شکل (14-14)

14-4-4- آرگومان‌‌هایی با طول‌‌متغیر

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

شکل (14-15)
شکل (14-15)

در این حالت، قبل از نام متغیر، یک علامت ستاره قرار می‌‌گیرد. این متغیر، مقادیر تمام آرگومان‌‌های غیرکلیدی را در خود نگه می‌‌دارد. در صورتی که در زمان فراخوانی تابع، هیچ آرگومان اضافی، نیاز نباشد، مقدار این متغیر، خالی در نظرگرفته می‌‌شود. در شکل (14-16) سعی‌‌کردیم، یک مثال ساده از این نوع را به شما نشان‌‌دهیم.

شکل (14-16)
شکل (14-16)

خروجی اجرای این قطعه کد، به شکل (14-17) خواهدبود.

شکل (14-17)
شکل (14-17)

14-5- توابع ناشناس[1]

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

  • انواع مختلف لامبدا می‌‌تواند تعداد دلخواهی از آرگومان‌‌ها را داشته‌‌باشد، اما فقط یک مقدار را به صورت نمایش یک عبارت، برمی‌‌گرداند. آن‌‌ها قادر به برگرداندن دستورات و عبارات متعدد نیستند.
  • به دلیل این که، لامبدا نیازمند یک عبارت است، این توابع نمی‌‌توانند یک فراخوانی مستقیم را برای چاپ یک عبارت داشته‌‌باشد.
  • توابع لامبدا، فضای اسمی[2] محلی مخصوص به خود را دارند و نمی‌‌توانند به غیر از متغیرهایی که برایشان فهرست شده‌‌است ویا آن‌‌هایی که در فضای اسمی عمومی[3] قرار دارند، دسترسی پیدا‌‌کنند.
  • اگر چه به نظر می‌‌رسد که لامبدا نسخه‌‌ای از توابع تک خطی هستند، اما نمی‌‌توان آن‌‌ها را معادل این نوع توابع در زبان C ویا C++ درنظر گرفت. توابع تک خطی در زبان‌‌های ذکرشده، برای عبور دادن پشته‌‌ی توابع، برای بهبود کارایی در زمان فراخوانی استفاده می‌‌شوند.

شمای کلی توابع لامبدا، به صورت شکل (14-18) خواهدبود. مثال شکل (14-19)، نمونه‌‌ای از تعریف و فراخوانی این نوع توابع را نشان می‌‌دهد.

شکل (14-18)
شکل (14-18)
شکل (14-19)
شکل (14-19)

خروجی اجرای این قطعه کد، به شکل (14-20) است. همان گونه که مشاهده می‌‌کنید، هیچ نیازی به ورود مقادیر همه‌‌ی آرگومان‌‌ها در این توابع نیست.

شکل (14-20)
شکل (14-20)
[1]The Anonymous Functions [2]NameSpace [3]Global

14-6- حوزه‌‌ی متغیرها[1]

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

متغیرهایی که داخل بدنه‌‌ی تابع تعریف شده‌‌اند را متغیرهای محلی و آن‌‌هایی که در خارج از بدنه تعریف می‌‌شوند را متغیرهای سراسری (جهانی) می‌‌نامیم. بنابراین متغیرهای محلی، فقط در داخل تابعی که در آن تعریف شده‌‌اند، قابل دسترسی هستند. در حالی که، متغیرهای سراسری را می‌‌توان در بخش‌‌های مختلف برنامه و توسط هر تابعی به کار برد. همچنین زمانی ‌‌که تابعی فراخوانی می‌‌شود، متغیرهای درون آن، در دسترس قرارگرفته و بعد از فراخوانی، از دسترس خارج می‌‌شوند. در شکل (14-21) مثال ساده‌‌ای را در این رابطه آورده‌‌ایم.

شکل (14-21)
شکل (14-21)

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

شکل (14-22)
شکل (14-22)
[1]Scope of Variables [2]Global variables

در پست بعدی به ماژول خواهیم پرداخت. با ما همراه باشین.

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