توابع درجه یک، توابع درجه بالاتر و بسته شدن در پایتون – با مثال کد توضیح داده شده است


در برنامه نویسی مدرن، درک مفاهیمی مانند توابع درجه یک، توابع درجه بالاتر و بسته شدن مهم است. این ایده ها به ما کمک می کند تا کدی انعطاف پذیر و کارآمد بنویسیم. آنها همچنین بلوک های سازنده بسیاری از تکنیک های کدنویسی پیشرفته هستند.
توابع درجه یک و توابع درجه بالاتر به ما این امکان را می دهند که توابع را به عنوان متغیر در نظر بگیریم و کد ما را قدرتمندتر و قابل استفاده مجدد می کند. بسته شدن این کار را با اجازه دادن به توابع برای به خاطر سپردن متغیرها از محدوده خود یک قدم فراتر می برد.
این آموزش به این مفاهیم می پردازد و نحوه ارتباط آنها را با مثال های کدگذاری عملی برای نشان دادن استفاده از آنها توضیح می دهد.
فهرست مطالب
توابع درجه یک
- اختصاص توابع به متغیرها
- عبور توابع به عنوان آرگومان
- برگرداندن توابع از سایر توابع
توابع مرتبه بالاتر
- توابع لامبدا
- تابع مرتبه بالاتر که تابعی را به عنوان آرگومان می گیرد
- تابع مرتبه بالاتر که عملکرد دیگری را برمی گرداند
بسته شدن
– بستن پایه (عملکرد تودرتوی پایه با اجرای فوری)
- برگرداندن عملکرد داخلی
- استفاده از بسته شدن با پارامترها
برای درک کامل بستهها، ابتدا باید مفاهیم توابع درجه یک و توابع درجه بالاتر را درک کنید. این مفاهیم سنگ بنای بسیاری از الگوهای برنامه نویسی پیشرفته هستند و برای عملکرد بسته ها اساسی هستند. بیایید به این مفاهیم و چگونگی ارتباط آنها بپردازیم.
توابع درجه یک
در برنامه نویسی، اگر زبانی با توابع به عنوان شهروندان درجه یک رفتار کند، گفته می شود که دارای توابع درجه یک است. این بدان معنی است که توابع در چنین زبانی می توانند:
به متغیرها اختصاص داده شده است
به عنوان آرگومان به توابع دیگر منتقل می شود
از توابع دیگر برگشته است
به عبارت ساده تر، توابع درجه یک را می توان مانند هر متغیر یا شی دیگری در زبان مدیریت کرد. بیایید با چند مثال کدنویسی این قابلیت ها را تحلیل کنیم.
اختصاص توابع به متغیرها
به طور معمول، ما یک تابع را فراخوانی می کنیم و نتیجه آن را به یک متغیر اختصاص می دهیم. برای مثال:
در اینجا، add
تابعی است که مجموع دو عدد را برمی گرداند. وقتی add(3, 4)
فراخوانی می کنیم، 7
برمی گرداند که به result
متغیر اختصاص داده می شود. خروجی این کد خواهد بود:
<function add at 0x...> 7
حالا بیایید تابع add
را به یک متغیر sum_function
بدون فراخوانی (یعنی بدون پرانتز) اختصاص دهیم.
sum_function = add
چاپ add
و sum_function
نشان می دهد که هر دو به یک شی تابع اشاره دارند:
print(add) # Outputs: <function square at 0x...> print(sum_function) # Outputs: <function square at 0x...>
این نشان می دهد که توابع را می توان مانند هر نوع داده دیگری به متغیرها اختصاص داد. اکنون میتوانیم از sum_function
درست مانند تابع add
اصلی استفاده کنیم و حتی نام تابع اصلی add
را حذف کنیم، و تابع همچنان از طریق sum_function
قابل دسترسی خواهد بود.
del add print(sum_function(3, 4)) # Output: 7
عبور توابع به عنوان آرگومان
یکی دیگر از جنبه های توابع درجه یک، توانایی انتقال آنها به عنوان آرگومان به توابع دیگر است. این به انعطاف پذیری و ماژولار بودن بیشتر در کد اجازه می دهد.
بیایید این را با یک تابع map
سفارشی نشان دهیم. یک تابع map
یک تابع داده شده را برای هر آیتم در یک فهرست (یا آرایه) اعمال می کند و یک فهرست جدید با نتایج را برمی گرداند.
در این مثال، تابع double
یک عدد n
می گیرد و دو برابر آن را برمی گرداند. تابع map_function
یک func
تابع و فهرست ی از values
را می گیرد، func
برای هر عنصر در values
اعمال می کند و یک فهرست جدید با نتایج برمی گرداند.
هنگامی که map_function
با double
و فهرست [3, 6, 9, 12, 15]
فراخوانی می شود، تابع double
را برای هر عنصر در فهرست اعمال می کند که نتیجه آن [6, 12, 18, 24, 30]
است. این نشان می دهد که چگونه توابع را می توان به عنوان آرگومان برای ایجاد الگوهای کد انعطاف پذیر و قابل استفاده مجدد ارسال کرد.
توجه داشته باشید که هنگام ارسال تابع، پرانتز را وارد نمیکنیم (یعنی به جای double()
double
، که نشان میدهد خود تابع را ارسال میکنیم و نتیجه فراخوانی تابع نیست.
برگرداندن توابع از سایر توابع
برگرداندن توابع از توابع دیگر یکی دیگر از ویژگی های مهم توابع درجه یک است. این مفهوم امکان ایجاد کدهای پیچیده تر و ماژولار را فراهم می کند که اغلب در سناریوهایی مانند ایجاد توابع قابل تنظیم یا بسته شدن استفاده می شود.
برای توضیح بیشتر، اجازه دهید به یک مثال عملی نگاه کنیم که در آن یک تابع تابع دیگری را برمی گرداند:
در این مثال، تابع create_multiplier
یک factor
پارامتر را می گیرد و multiplier
تابع دیگری را برمی گرداند. این تابع multiplier
وقتی با آرگومان x
فراخوانی می شود، حاصلضرب x
و factor
را برمی گرداند.
وقتی create_multiplier
با 2
فراخوانی می شود، تابعی را برمی گرداند که آرگومان خود را در 2
ضرب می کند. به طور مشابه، هنگامی که با 3
فراخوانی می شود، تابعی را برمی گرداند که آرگومان خود را در 3
ضرب می کند. این توابع بازگشتی ( double
و triple
) را می توان با آرگومان هایی برای انجام ضرب فراخوانی کرد. برای مثال double(5)
10
و triple(5)
15
را برمی گرداند.
این ماهیت یک بسته شدن است – جایی که تابع برگشتی ( multiplier
) دسترسی به متغیر ( factor
) را از محدوده محصور خود حفظ می کند، حتی پس از اتمام اجرای تابع خارجی ( create_multiplier
). این به توابع ایجاد شده ( double
و triple
) اجازه می دهد تا مقدار factor
که با آن ایجاد شده اند را به خاطر بسپارند و از آن استفاده کنند.
توابع مرتبه بالاتر
تابع مرتبه بالاتر تابعی است که روی توابع دیگر عمل می کند. به طور خاص، یک تابع مرتبه بالاتر می تواند:
یک یا چند تابع را به عنوان آرگومان در نظر بگیرید
یک تابع را به عنوان نتیجه آن برگردانید
اساساً، توابع مرتبه بالاتر از توابع درجه یک استفاده می کنند تا آنها را به عنوان آرگومان در نظر بگیرند یا آنها را به عنوان نتیجه برگردانند و عملیات قدرتمندی را روی خود توابع ممکن می سازند. نمونههایی از هر دو را قبلاً دیدهایم:
در مثال " عبور توابع به عنوان آرگومان " ما، map_function
یک تابع مرتبه بالاتر است زیرا تابع ( double
) را به عنوان آرگومان می گیرد.
در مثال " بازگرداندن توابع از توابع دیگر "، create_multiplier
یک تابع مرتبه بالاتر است زیرا تابع دیگری ( multiplier
) را در نتیجه برمی گرداند.
قبل از اینکه به سمت بسته شدن حرکت کنیم، اجازه دهید به سرعت در مورد توابع لامبدا بحث کنیم، زیرا آنها لایه دیگری از انعطاف پذیری را اضافه می کنند و کد مختصر و گویاتر را امکان پذیر می کنند.
توابع لامبدا
توابع لامبدا در پایتون که با نام توابع ناشناس نیز شناخته می شوند، توابع کوچکی هستند که با استفاده از کلمه کلیدی lambda
تعریف می شوند. آنها اغلب برای کارهای کوتاه مدت استفاده می شوند که نیازی به تعریف کامل تابع با def
ندارند.
آنها اساسا قند نحوی برای تعریف توابع کوچک هستند. نحو یک تابع لامبدا به صورت زیر است:
lambda arguments: expression
توابع لامبدا را می توان به عنوان آرگومان به توابع درجه بالاتر ارسال کرد یا از آنها بازگرداند و آنها را به ابزارهای همه کاره در برنامه نویسی تابعی تبدیل کرد.
مثال: استفاده از توابع لامبدا در یک تابع نقشه سفارشی
ما قبلاً مثال map_function
را مورد بحث قرار دادیم. بیایید ببینیم چگونه می توانیم با استفاده از یک تابع لامبدا به همان عملکرد دست پیدا کنیم:
در این مثال، تابع لامبدا lambda n: n * 2
مستقیماً به map_function
ارسال می شود و نیاز به تعریف تابع double
جداگانه را از بین می برد.
مثال: ایجاد توابع ضرب کننده با Lambdas
با مشاهده مجدد مثال create_multiplier
، می توانیم از یک تابع لامبدا برای multiplier
استفاده کنیم:
در اینجا، create_multiplier
یک تابع لامبدا را برمیگرداند که ورودی آن را در factor
مشخص شده ضرب میکند. این یک روش فشرده و گویا برای تعریف عملکرد یکسان است.
برای درک عمیق تر از توابع لامبدا، می توانید این آموزش را در اینجا تحلیل کنید.
وابستگی متقابل توابع مرتبه بالاتر و توابع درجه یک:
کارکردهای مرتبه بالاتر پیامد مستقیم شهروند درجه یک بودن عملکردها هستند. اگر بتوان با توابع مانند هر مقدار دیگری رفتار کرد، طبیعتاً نتیجه می شود که می توانید توابع را به توابع دیگر منتقل کنید و آنها را از توابع دیگر برگردانید.
پس می توانیم بگوییم - توابع مرتبه بالاتر ذاتاً بر مفهوم توابع درجه یک متکی هستند. بدون توابع درجه یک، نمیتوانیم توابع درجه بالاتری داشته باشیم، زیرا توابع دوم به توانایی ارسال و برگرداندن توابع بستگی دارد.
بیایید با مثال های بیشتری بفهمیم:
مثال: تابعی با مرتبه بالاتر که تابعی را به عنوان آرگومان می گیرد (تابع درجه اول)
در این مثال، apply_operation
یک تابع مرتبه بالاتر است زیرا تابع دیگری ( operation
) را به عنوان آرگومان می گیرد. توابع add
و multiply
توابع درجه یک هستند زیرا می توانند به عنوان آرگومان به توابع دیگر ارسال شوند.
تابع apply_operation
سه پارامتر دارد: یک تابع ( operation
) و دو عدد صحیح ( x
و y
). نتیجه اعمال تابع operation
را به x
و y
برمی گرداند.
با فراخوانی apply_operation(add, 3, 4)
7 را برمی گرداند که حاصل جمع 3 و 4 است. به همین ترتیب، فراخوانی apply_operation(multiply, 3, 4)
عدد 12 را برمی گرداند که حاصل ضرب 3 و 4 است. این انعطاف پذیری و انعطاف پذیری را نشان می دهد. قابلیت استفاده مجدد از توابع مرتبه بالاتر، نشان می دهد که چگونه می توانیم عملیات متفاوتی را در مجموعه ورودی های یکسان انجام دهیم.
مثال: یک تابع مرتبه بالاتر که تابع دیگری را برمی گرداند (تابع درجه اول)
در این مثال، discount_applier
یک پارامتر discount_rate
می گیرد و یک تابع جدید apply_discount
برمی گرداند. این باعث می شود که آن یک "عملکرد مرتبه بالاتر" باشد و apply_discount
به عنوان "عملکرد درجه یک" در نظر گرفته می شود زیرا در داخل discount_applier
تعریف شده و برای استفاده بعدا برگردانده می شود.
این تابع apply_discount
، هنگامی که با آرگومان price
فراخوانی می شود، قیمت تخفیف خورده محاسبه شده با استفاده از discount_rate
را برمی گرداند.
هنگامی که discount_applier
با نرخ تنزیل 20 فراخوانی می شود، تابعی را برمی گرداند که 20% تخفیف به آرگومان خود اعمال می کند. به طور مشابه، هنگامی که با نرخ تخفیف 15 فراخوانی می شود، تابعی را برمی گرداند که 15 درصد تخفیف اعمال می کند. این توابع برگشتی ( holiday_discount
و member_discount
) می توانند برای اعمال تخفیف های مربوطه استفاده شوند.
با فراخوانی holiday_discount(100)
، 80.0 را برمی گرداند، با اعمال 20% تخفیف به 100. تماس با member_discount(100)
85.0 را برمی گرداند، با اعمال 15% تخفیف.
این مثالها نشان میدهند که چگونه توابع درجه بالاتر با استفاده از قابلیتهای توابع درجه یک، ایجاد الگوهای کد انعطافپذیر، قابل استفاده مجدد و مدولار را امکانپذیر میسازند. آنها پایه و اساس بسیاری از تکنیک های برنامه نویسی پیشرفته از جمله بسته شدن را تشکیل می دهند و برای نوشتن کدهای رسا و قدرتمند ضروری هستند.
بسته شدن
بسته شدن یک ویژگی در بسیاری از زبانهای برنامهنویسی از جمله پایتون است که به یک تابع اجازه میدهد تا متغیرها را حتی پس از پایان اجرای تابع بیرونی از یک محدوده محصور به خاطر بسپارد و به آن دسترسی پیدا کند.
به عبارت ساده تر، بسته شدن یک تابع درونی است که به متغیرهای تابع حاوی (یا بیرونی) خود دسترسی دارد، حتی پس از اتمام اجرای آن تابع خارجی.
بیایید به چند مثال نگاه کنیم تا بفهمیم بسته شدن در پایتون چگونه کار می کند:
تابع تودرتوی پایه با اجرای فوری
در این مثال، تابع outer_scope
دو متغیر محلی را تعریف میکند: name
و city
. سپس تعریف میکند و بلافاصله inner_scope
را فرا میخواند، که یک پیام تبریک با استفاده از متغیرهای name
و city
از محدوده محصور چاپ میکند.
هنگامی که outer_scope
فراخوانی می شود، تابع تودرتو inner_scope
اجرا می شود و پیام تبریک را تولید می کند: "سلام سام، درود از نیویورک".
بازگرداندن عملکرد درونی
حالا بیایید مثال را تغییر دهیم تا تابع داخلی بدون اجرای فوری آن را برگردانیم:
در اینجا outer_scope
name
و city
به عنوان متغیرهایی مشابه مثال بالا تعریف می کند. سپس تابع inner_scope
را تعریف و برمی گرداند اما این بار بدون فراخوانی آن (یعنی inner_scope
به جای inner_scope()
)
هنگامی که greeting_func = outer_scope()
اجرا می شود، تابع inner_scope
را که توسط outer_scope
برگردانده شده است به greeting_func
اختصاص می دهد.
اکنون، greeting_func
اشاره ای به تابع inner_scope
دارد. فراخوانی greeting_func()
inner_scope
را اجرا میکند که چاپ میکند: "سلام سام، درود از نیویورک".
حتی اگر زمانی که ما greeting_func()
را فراخوانی می کنیم outer_scope
به پایان رسیده است، تابع inner_scope
(اکنون توسط greeting_func
ارجاع داده شده است) دسترسی به name
متغیرها و city
را از محدوده خود حفظ می کند. این چیزی است که آن را به یک بسته تبدیل می کند - متغیرها را از محدوده حاوی خود "بسته است".
استفاده از بسته شدن با پارامترها
برای نشان دادن قدرت بسته شدن، بیایید با گفت ن پارامترهایی به تابع outer_scope
یک مثال پویاتر ایجاد کنیم:
اکنون در اینجا، تابع outer_scope
name
و city
را به عنوان پارامتر می گیرد. در داخل outer_scope
، تابع inner_scope
برای چاپ پیام تبریک با استفاده از name
و city
تعریف شده است. به جای فراخوانی inner_scope
، outer_scope
خود تابع inner_scope
را برمی گرداند.
وقتی outer_scope
با آرگومانهای خاص فراخوانی میشود، بستهای ایجاد میکند و برمیگرداند که این آرگومانها را جمعآوری میکند. به عنوان مثال، greet_priyanshu
بسته ای است که Dr Priyanshu
و Jaipur
را به یاد می آورد، در حالی که greet_sam
Sam
و New York
را به یاد می آورد. هنگامی که این بسته ها فراخوانی می شوند، پیام های تبریک مربوطه را تولید می کنند.
حتی اگر outer_scope
در هر دو مورد اجرا را به پایان رسانده است، توابع inner_scope
(اکنون greet_priyanshu
و greet_sam
) دسترسی به name
و متغیرهای city
مربوطه را از محدودههای محصور خود حفظ میکنند و رفتار بسته شدن را نشان میدهند.
اگر می خواهید، می توانید به جای تابع داخلی ما ( inner_scope
) از یک تابع لامبدا نیز استفاده کنید:
با استفاده از یک تابع لامبدا، به روشی مختصرتر به همان نتیجه می رسیم. بستههای ایجاد شده توسط outer_scope
همچنان دسترسی به متغیرهای name
و city
را حفظ میکنند و همین رفتار بسته شدن را نشان میدهند.
کاربردهای دنیای واقعی بستن
اکنون اجازه دهید برخی از کاربردهای عملی بسته شدن در برنامه نویسی دنیای واقعی را ببینیم. در اینجا چند سناریو وجود دارد که معمولاً از بسته شدن استفاده می شود:
مدیریت رویداد در توسعه وب (نمونه js اما مورد استفاده مهم)
در جاوا اسکریپت، بستن اغلب برای مدیریت رویدادها، مانند کلیک روی دکمه، استفاده می شود.
توضیح :
createButtonHandler
یک تابع مرتبه بالاتر است که یک buttonName
به عنوان آرگومان می گیرد و یک تابع (بسته شدن) را برمی گرداند.
تابع بازگشتی (بستن) متغیر buttonName
از محدوده واژگانی خود می گیرد.
هنگامی که یک دکمه کلیک می شود، بسته شدن مربوطه فراخوانی می شود و به buttonName
که هنگام ایجاد کنترل کننده ارسال شده است دسترسی دارد.
حفظ وضعیت در برنامه های رابط کاربری گرافیکی
در پایتون، بستهها را میتوان برای حفظ حالت در برنامههای رابط کاربری گرافیکی (GUI) استفاده کرد، مانند مواردی که با Tkinter ایجاد شدهاند.
توضیح :
create_counter
یک تابع مرتبه بالاتر است که count
به 0 مقداردهی اولیه می کند و یک تابع counter
تودرتو تعریف می کند.
تابع counter
یک بسته است که متغیر count
از محدوده محصور می گیرد.
کلمه کلیدی nonlocal
به بسته شدن اجازه می دهد تا متغیر count
را تغییر دهد.
هر بار که روی دکمه کلیک می شود، تابع counter
فراخوانی می شود و count
افزایش داده و چاپ می کند.
برخی از برنامه های کاربردی دیگر عبارتند از:
ایجاد دکوراتورها
دکوراتورها در پایتون ابزاری قدرتمند برای اصلاح یا گسترش رفتار توابع و روشها هستند. بسته شدن مکانیسم اساسی برای اجرای دکوراتورها است.
پنهان کردن و کپسوله کردن داده ها
می توان از بسته ها برای ایجاد متغیرها و متدهای خصوصی در یک تابع استفاده کرد که فقط توسط تابع داخلی قابل دسترسی و تغییر هستند. این روشی را برای دستیابی به کپسوله سازی در پایتون فراهم می کند.
نتیجه
توابع درجه یک به ما این امکان را می دهند که توابع را مانند هر شی یا نوع داده دیگری در نظر بگیریم و انعطاف پذیری را برای موارد زیر ارائه کنیم:
این قابلیت یک جنبه اساسی از بسیاری از تکنیک های برنامه نویسی پیشرفته از جمله بسته شدن است. درک توابع درجه یک اولین قدم در تسلط بر این مفاهیم پیچیده تر است.
از سوی دیگر، توابع مرتبه بالاتر این را یک گام فراتر می برند. آنها نه تنها به شما اجازه می دهند با توابع مانند داده رفتار کنید، بلکه به شما امکان می دهند از توابع برای ایجاد توابع جدید یا تغییر نحوه رفتار سایر توابع استفاده کنید. این راه را به روی راه های پیچیده تر و انعطاف پذیرتر برای حل مسائل در برنامه نویسی باز می کند.
آنها عملیاتی مانند:
در حالی که همه توابع درجه بالاتر شامل توابع درجه یک هستند، همه توابع درجه یک لزوماً توابع درجه بالاتر نیستند.
به طور خلاصه، بستهها به توابع داخلی اجازه میدهند تا به متغیرها از محدوده خود دسترسی داشته باشند.
متغیرهای آزاد متغیرهایی هستند که در یک تابع درونی استفاده می شوند اما در یک تابع بیرونی تعریف می شوند.
استفاده عملی از بسته شدن شامل سناریوهایی است که در آن شما نیاز به توابع برای به خاطر سپردن وضعیت دارید، حتی پس از اتمام اجرای تابع خارجی.
ارسال نظر