«توابع تو در تو در پایتون» (Nested Function in Python)، یکی از مفاهیم جذاب در برنامهنویسی است که اشاره به تعریف یک تابع درون تابعی دیگر دارد. این توابع تو در تو که با نام «توابع درونی» (Inner Functions) نیز شناخته می شوند، توانایی بینظیری در دسترسی به متغیرهای محدوده خود دارند. به بیان سادهتر، آنها میتوانند از منابع تابع والد خود بهرهمند شوند. توابع تو در تو در پایتون یکی از ابزارهای قدرتمند این زبان محسوب میشوند و به ما امکان میدهند تابعی را درون تابعی دیگر تعریف کنیم. این مفهوم با استفاده از جایگذاری یک تابع درون تابعی دیگر، کمک میکند تا کدهای منظمتر و مدیریتپذیرتری را ایجاد کنیم. به لطف وجود مفهوم Nested Functions، کدها خواناتر و همچنین بهینهتر میشوند. در این مطلب از مجله فرادرس توضیح میدهیم که توابع تو در تو در پایتون چیست و به چه دلیلی از آن استفاده میکنیم.
مقدمهای بر توابع در پایتون
در این قسمت، بهطور مختصر مروری بر مفاهیم اولیه این موضوع، نظیر تابع در پایتون و برنامهنویسی تابعی خواهیم داشت.
توابع در پایتون
«توابع» (Functions) نقش مهمی را در برنامهنویسی به زبان پایتون بر عهده دارند. فانکشنها در واقع قطعه کدهایی با قابلیت استفاده مجدد هستند که میتوانند وظایف مشخصی را انجام دهند. پس از تعریف تابع، با استفاده از نام آن و - در صورت لزوم - ارسال آرگومانهایی در پرانتز، میتوانیم آن را فراخوانی کنیم. برای انجام وظایف مختلف میتوانیم توابع متعددی را تعریف کنیم که هر یک وظیفه خاص خود را دارند. با این کار کدهایمان راحتتر سازماندهی و ساختارمند میشوند. مستندسازی و تایپدهی تابع، مؤلفههای مهمی برای خوانایی کدها و دیباگ راحتتر آن بهشمار میروند، بهخصوص هنگامیکه با پروژههای بزرگ سر و کار داریم.
برنامه نویسی تابعی
زبان برنامهنویسی پایتون از پارادایمها یا الگوهای برنامهنویسی متعددی نظیر «برنامهنویسی تابعی» (Functional Programming) پشتیبانی میکند. این رویکرد برنامهنویسی به استفاده از توابع خالص، بدون استفاده از وضعیت مشترک، دادههای «تغییرپذیر» (Mutable) و «اثرات ناخواسته» (Side-Effects) معطوف است. بهطور معمول این رویکرد در پایتون بهوسیله بهکارگیری توابع «مرتبهبالاتر» (Higher-Order) و عبارات لامبدا یا lambda
u200aمورد استفاده قرار میگیرد.
منظور از توابع تو در تو در پایتون چیست؟
توابع تو در تو در پایتون به مفهومی در این زبان برنامهنویسی گفته میشود که در آن تابعی را درون تابعی دیگر ایجاد میکنیم. به بیان دیگر، یک تابع را میتوانیم داخل تابعی دیگر تعریف کنیم سپس این تابع میتواند به متغیرهای اعلان شده در تابع بیرونی خود دسترسی داشته باشد.
چه زمانی از توابع تو در تو در پایتون استفاده می کنیم؟
توابع تو در تو در پایتون زمانی مفید هستند که نیازمند تعریف تابع کمکی هستیم که تنها داخل محدوده «تابع بیرونی» (Outer Function) مورد نیاز است. توابع تو در تو در پایتون افزون بر اینکه خوانایی کدهایمان را افزایش میدهند، به سازماندهی و ماژولارسازی کدها نیز کمک میکنند.
مثال توابع تو در تو در پایتون
در این بخش از مطلب مجله فرادرس میخواهیم نمونههایی از نِستِدفانکشن یا همان توابع تو در تو در پایتون را با هم مرور کنیم.
مثال اول از توابع تو در تو در پایتون
در زیر، مثالی از توابع تو در تو آورده شده است.
def outer_function(x):
def inner_function(y):
retu x + y
retu inner_function
add_five = outer_function(5)
print(add_five(3))
خروجی این کدها را در ادامه آوردهایم.
8
توضیح کدها
در این مثال، ۲ تابع به نامهای آورده شده در زیر تعریف کردهایم.
outer_function
inner_function
تابع outer_function
u200aآرگومانی ورودی بهنام x
u200aرا دریافت کرده و تابع inner_function
u200aرا بهعنوان خروجی برمیگرداند. بههمین ترتیب، تابع inner_function
آرگومان y
u200aرا دریافت کرده و مجموع x
و y
را بر میگرداند.
خروجی تابع outer_function(5)
u200aرا به متغیر add_five
u200aتخصیص میدهیم که تبدیل به تابعی شده و مقدار 5
u200aرا به آرگومان خود اضافه میکند. هنگامیکه add_five(3)
u200aرا فراخوانی میکنیم، نتیجهای برابر با 8
u200aدریافت خواهیم کرد.
مثال دوم از توابع تو در تو در پایتون
در زیر، مثال دیگری از توابع تو در تو را بررسی میکنیم.
def outer_function():
x = 1
def inner_function():
y = 2
retu x + y
retu inner_function()
print(outer_function())
خروجی این کدها را در ادامه آوردهایم.
3
توضیح کدها
در این مثال، تابعی بهنام outer_function
تعریف کردهایم که مقدار اولیه 1
u200aرا به x
نسبت میدهد و خروجی inner_function
را بر میگرداند. inner_function
متغیر y
را با 2
u200aمقداردهی میکند و مجموع x
و y
را بر میگرداند.
زمانیکه تابع outer_function
را فراخوانی میکنیم مقدار 3
u200aرا بهعنوان نتیجه، دریافت خواهیم کرد که مجموع متغیرهای x
و y
است. تابع inner_function
درون محدوده outer_function
فراخوانی میشود و به متغیر x
- تعریف شده درون تابع outer_function
- دسترسی خواهد داشت.
مزایای استفاده از توابع تو در تو در پایتون
بهکارگیری توابع تو در تو در پایتون دارای مزیتهای بسیاری است. این قابلیت به برنامهنویسان امکان میدهد تا ساختار برنامهنویسی تطبیقپذیر و قویتری را ایجاد کنند، خوانایی کدهایشان را افزایش دهند و با ایجاد کدهای ماژولار، فرایند نگهداری از آن را تسهیل کنند.
«کپسولهسازی و ماژولار بودن» (Encapsulation and Modularity): مهمترین مزیت توابع تو در تو در پایتون، به توانایی آن در تعریف توابع کمکی درون محدوده خاص یک تابع متکی است. در نتیجه این کار، ضمن ترویج سازماندهی کدها، از بینظمی و شلوغی Namespace عمومی پیشگیری میشود. برای نمونه، مثال زیر را در نظر میگیریم.
def double_odd_numbers(numbers):
def is_odd(num):
retu num % 2 != 0
def double(num):
retu num * 2
retu [double(num) for num in numbers if is_odd(num)]
در این مثال، double_odd_numbers
u200aتوابع is_odd
u200aو double
u200aرا در بر میگیرد که درک آن را آسان میکند چون این توابع تنها در محدوده تابع اصلی استفاده میشوند.
«ایجاد بستار» (Closure Creation): مزیت قابل توجه دیگری که توابع تو در تو در پایتون برایمان فراهم میکنند، توانایی آنها در ایجاد بستارها است. این قابلیت به توابع تو در تو امکان میدهد تا به متغیرها، از تابع دربرگیرنده خود دسترسی پیدا کرده و تغییرات مربوطه را روی آنها اعمال کنند. برای مثال، قطعه کدهای زیر را در نظر میگیریم.
def power_function(base):
def exponent_power(exponent):
result = 1
for _ in range(exponent):
result *= base
retu result
retu exponent_power
square = power_function(2)
cube = power_function(3)
print(square(3))
print(cube(2))
خروجی این کدها به صورت زیر خواهد بود.
8
9
در این حالت، تابع power_function
u200aتابع جدیدی بهنام exponent_power
u200aایجاد میکند که میتواند مقدار توان یک پایه base
u200a- به توان دادهشده - را محاسبه کند. با بهکارگیری این ساختار تو در تو، توابعی مانند square
u200aو cube
u200aبه متغیر base
u200aاز تابع دربرگیرنده، دسترسی پیدا کرده و ایجاد توابع جدید با مقادیر base
متفاوت را تسهیل میکنند.
با بهرهگیری از توابع تو در تو در پایتون، توسعهدهندگان این زبان میتوانند خوانایی و ماژولار بودن کدهای خود را افزایش دهند و از عملکردهای قدرتمند بستاری برای ایجاد ساختارهای متنوع و کارآمد تر استفاده کنند.
ایجاد توابع تو در تو در پایتون چگونه است؟
توابع تو در تو در پایتون به فرایند ایجاد یا همان تعریف تابعی درون تابعی دیگر اشاره دارد. این روند به سازماندهی بهتر و افزایش خوانایی کدها کمک بهسزایی میکند. برای ایجاد یک تابع تو در تو در پایتون، کافی است تا مراحل آورده شده در ادامه را دنبال کنیم.
«تابع بیرونی» (Outer Function) را میسازیم.
«تابع درونی» (Inner Function) را داخل تابع بیرونی تعریف میکنیم.
تابع درونی را داخل تابع بیرونی فراخوانی میکنیم یا - به عنوان نتیجه آن - بر میگردانیم.
همانطور که پیشتر هم بیان کردیم، ایجاد توابع تو در تو در پایتون، روش مفیدی برای سازماندهی و سادهسازی کدها محسوب میشود. همچنین، فرایندهای پیچیده را ساده میسازد و به خوانایی بهتر کدها نیز کمک میکند.
مثال های توابع تو در تو پایتون در کاربردهای واقعی
Nested Function-ها توابعی هستند که درون توابع دیگر تعریف شدهاند. ایجاد توابع به این شکل در برنامهنویسی، کاربرد زیادی دارد و میتواند در کاربردهای واقعی پایتون مورد استفاده قرار گیرد. بهطور مثال، یک تابع تو در تو میتواند تابعی را تعریف کرده که تابع دیگری را فراخوانی میکند. یا در مثالی دیگر یک تابع تو در تو میتواند تابعی را تعریف کرده که از تابع از پیشتعریف شدهای استفاده میکند. افزون بر این، تابع تو در تو میتواند «محدوده محلی» (Local Scope) را نیز در اختیارمان قرار دهد.
مثال اول
کدهای آورده شده در ادامه را در نظر بگیرید.
def parent_function(x):
def child_function(y):
retu y * 2
retu x + child_function(x)
print(parent_function(5))
در این مثال، تابع child_function
u200aیک تابع تو در تو محسوب میشود که درون تابع parent_function
u200aتعریف شده است. تابع parent_function
پارامتری بهنام x
u200aرا دریافت میکند. سپس از تابع child_function
برای دوبرابر کردن مقدار آن استفاده میکند. در نهایت، مجموع x
و child_function
را بر میگرداند. با اجرای parent_function(5)
u200aمقدار 15
u200aبه عنوان نتیجه دریافت میکنیم.
مثال دوم
مثال دیگری در این رابطه آوردهایم.
def adder(a):
def inner(x):
retu x + a
retu inner
x = adder(3)
y = adder(5)
print(x(5))
print(y(5))
در این مثال، inner
u200aیک تابع تو در تو است که درون تابع adder
u200aتعریف شده است. تابع adder
پارامتری بهنام a
u200aرا دریافت و تابع inner
را بر میگرداند. تابع inner
پارامتری بهنام x
u200aرا دریافت و مجموع x
و a
را بر میگرداند. هنگامیکه adder(3)
u200aرا فراخوانی میکنیم، تابع inner
را دریافت خواهیم کرد. inner
را نیز بهعنوان x
ذخیره میکنیم. این مورد برای adder(5)
u200aهم صدق میکند که آن را بهعنوان y
u200aذخیره میکنیم. هنگامیکه x(5)
u200aباشد، نتیجهای برابر با 8
u200aخواهیم داشت و زمانیکه y(5)
u200aفراخوانی میکنیم، عدد 10
u200aرا بهعنوان خروجی دریافت خواهیم کرد.
مثال سوم
در ادامه این مطلب از مجله فرادرس، مثال دیگری را بررسی میکنیم.
def exponential(x):
def square(y):
retu y * y
retu square(x) * square(x)
print(exponential(2))
در این مثال، تابع square
u200aیک تابع تو در تو است که درون تابع exponential
u200aتعریف شده است. تابع exponential
پارامتری بهنام x
را دریافت کرده و مقدار مربع x
به توان چهارم را برمیگرداند. تابع square
پارامتری بهنام y
را دریافت کرده و مربع y
را بر میگرداند. با اجرای exponential(2)
u200a، مقدار 16
u200aرا بهعنوان نتیجه دریافت خواهیم کرد.
بهترین روش ها برای استفاده از توابع تو در تو در پایتون
بهترین روشها برای این توابع تو در تو شامل موراد زیر است.
پرهیز از زیادهروی در تو در تو سازی
اطمینان از اینکه هر تابع، هدف واضح و مشخصی دارد.
استفاده از محدوده متغیر مناسب.
برای استفاده از توابع تو در تو در پایتون، تابع بیرونی را تعریف کرده و سپس تابع درونی را داخل آن تعریف ميکنیم. تابع درونی بهمتغیرهای درون تابع بیرونی دسترسی خواهد داشت، اما عکس این قضیه برقرار نیست. در ادامه، ۲ مثال را در این باره آوردهایم.
# Example 1: Power function using nested functions
def power_function(num):
def inner_power(power):
retu num ** power
retu inner_power
# Example usage
square_function = power_function(2)
cube_function = power_function(3)
print(square_function(5)) # Output: 32
print(cube_function(5)) # Output: 243
در این مثال، تابع Power بهصورت تو در تو ایجاد شده است. تابع بیرونی، عددی را دریافت کرده و تابع درونی را - که توان آن عدد را محاسبه میکند - بهعنوان خروجی بر میگرداند. تابع درونی در محدوده تابع بیرونی تعریف شده است که به آن امکان میدهد به پارامتر num
u200aدسترسی داشته و توان را محاسبه کند.
مثال دیگری را در زیر آوردهایم.
# Example 2: Functions in a loop
def generate_functions():
functions = []
for i in range(5):
def inner_function(num):
retu num + i
functions.append(inner_function)
retu functions
# Example usage
functions_list = generate_functions()
for j, f in enumerate(functions_list):
print(f(j)) # Output: 4 5 6 7 8
در این مثال، با استفاده از یک حلقه و توابع تو در تو، لیستی از توابع تولید شده است. تابع درونی که داخل حلقه تعریف شده است، به آن امکان دسترسی به متغیر حلقه یعنی i
u200aرا میدهد. لیست حاصل از توابع پس از آن میتواند برای اجرای محاسبات با مقادیر گوناگون i
مورد استفاده قرار گیرد.
خطاهای متداول هنگام استفاده از توابع تو در تو در پایتون
برای پیشگیری از خطاهای رایج هنگام استفاده از توابع تو در تو در برنامهنویسی پایتون، اطمینان از اینکه نام توابع و متغیرها داخل تابع درونی و تابع والد آن تکرار نشده، اهمیت زیادی دارد، زیرا ممکن است سردرگمی و بروز خطا را بهدنبال داشته باشد.
خطاهای رایج دیگری که میبایست از آنها پرهیز کنیم شامل فراخوانی ناصحیح تابعی درون تابع دیگر و همچنین استفاده اشتباه از حلقهها درون توابع تو در تو است. افزون بر این، هنگام استفاده از روشهای برنامهنویسی تابعی میبایست دقت کافی به خرج دهیم.
بهطور مثال، کدهایی که در ادامه آوردهایم، خطای رایجی را نشان میدهد که متغیری در هر ۲ تابع والد و درونی تعریف شده است.
def parent_func():
num = 2
def nested_func():
num = num * 2 # This will raise an UnboundLocalError when the function will be called
retu num
retu nested_func()
سوالات متداول
اکنون که دانستیم توابع تو در تو در پایتون چیست و چگونه نوشته میشود و همچنین کارکرد آنها چگونه است، برخی از پرسشهای رایج در رابطه با آن را نیز در این قسمت پاسخ میدهیم.
منظور از تابع تو در تو چیست؟
همانطور که گفتیم، توابع تو در تو شامل تعریف یک تابع درون تابع دیگر است که این قضیه به کپسولهسازی و سازماندهی کدها کمک خواهد کرد.
فرق بین توابع ناشناس و توابع تو در تو در پایتون چیست؟
«توابع تو در تو» (Nested functions)، در واقع توابعی هستند که درون تابعی دیگر تعریف شدهاند.این توابع تنها از درون تابع در برگیرنده بیرونی قابل دسترسیاند. از سویی دیگر، «توابع ناشناس» (Anonymous Functions) را داریم که توابعی بدوننام هستند و با کلمه کلیدی lambda تعریف میشوند. این نوع توابع را میتوان در هر جایی از برنامه تعریف کرد و همچنین میتوانند بهعنوان آرگومان به تابع دیگر ارسال شوند.
جمعبندی
در این مطلب از مجله فرادرس به توضیح این مفهوم پرداختیم که توابع تو در تو در پایتون چیست و نحوه ایجاد این نوع توابع چگونه است. همچنین با مزایی که این روش برایمان فراهم میکند آشنا شدیم. همچنین، ضمن اینکه مثالهای متعددی را در مورد توابع تو در تو در پایتون بیان کردیم، کاربردهای واقعی استفاده از آن را نیز به همراه کدهای مرتبط توضیح دادیم.
هنگام نوشتن توابع تو در تو ممکن است با خطاهایی روبهرو شویم که برای رفع آنها نیز نکاتی را بیان کردیم. در آخر نیز به بیان برخی از پرسشهای متداول در این بلاره پرداختیم و پاسخهای مربوطه را با هم مرور کردیم.