«1 تو در تو در 1» (Nested Function in Python)، یکی از مفاهیم جذاب در برنامهنویسی است که اشاره به تعریف یک تابع درون تابعی دیگر دارد. این توابع تو در تو که با نام «توابع درونی» (Ier Functions) نیز شناخته می شوند، توانایی بینظیری در دسترسی به متغیرهای محدوده خود دارند. به بیان 1تر، آنها میتوانند از منابع تابع والد خود بهرهمند شوند. توابع تو در تو در پایتون یکی از ابزارهای قدرتمند این 1 محسوب میشوند و به ما امکان میدهند تابعی را درون تابعی دیگر تعریف کنیم. این مفهوم با استفاده از جایگذاری یک تابع درون تابعی دیگر، کمک میکند تا کدهای منظمتر و مدیریتپذیرتری را ایجاد کنیم. به لطف وجود مفهوم Nested Functions، کدها خواناتر و همچنین بهینهتر میشوند. در این مطلب از مجله فرادرس توضیح میدهیم که توابع تو در تو در پایتون چیست و به چه دلیلی از آن استفاده میکنیم.
در این قسمت، بهطور مختصر مروری بر مفاهیم اولیه این موضوع، نظیر تابع در پایتون و برنامهنویسی تابعی خواهیم داشت.
«توابع» (Functions) نقش مهمی را در برنامهنویسی به زبان پایتون بر عهده دارند. فانکشنها در واقع قطعه کدهایی با قابلیت استفاده مجدد هستند که میتوانند وظایف مشخصی را انجام دهند. پس از تعریف تابع، با استفاده از نام آن و - در صورت لزوم - ارسال آرگومانهایی در پرانتز، میتوانیم آن را فراخوانی کنیم. برای انجام وظایف مختلف میتوانیم توابع متعددی را تعریف کنیم که هر یک وظیفه خاص خود را دارند. با این کار کدهایمان راحتتر سازماندهی و ساختارمند میشوند. مستندسازی و تایپدهی تابع، مؤلفههای مهمی برای خوانایی کدها و دیباگ راحتتر آن بهشمار میروند، بهخصوص هنگامیکه با پروژههای بزرگ سر و کار داریم.

زبان برنامهنویسی پایتون از پارادایمها یا الگوهای برنامهنویسی متعددی نظیر «برنامهنویسی تابعی» (Functional Programming) پشتیبانی میکند. این رویکرد برنامهنویسی به استفاده از توابع خالص، بدون استفاده از وضعیت مشترک، دادههای «تغییرپذیر» (Mutable) و «اثرات ناخواسته» (Side-Effects) معطوف است. بهطور معمول این رویکرد در پایتون بهوسیله بهکارگیری توابع «مرتبهبالاتر» (Higher-Order) و عبارات لامبدا یا lambda u200aمورد استفاده قرار میگیرد.
توابع تو در تو در پایتون به مفهومی در این زبان برنامهنویسی گفته میشود که در آن تابعی را درون تابعی دیگر ایجاد میکنیم. به بیان دیگر، یک تابع را میتوانیم داخل تابعی دیگر تعریف کنیم سپس این تابع میتواند به متغیرهای اعلان شده در تابع بیرونی خود دسترسی داشته باشد.
توابع تو در تو در پایتون زمانی مفید هستند که نیازمند تعریف تابع کمکی هستیم که تنها داخل محدوده «تابع بیرونی» (Outer Function) مورد نیاز است. توابع تو در تو در پایتون افزون بر اینکه خوانایی کدهایمان را افزایش میدهند، به سازماندهی و ماژولارسازی کدها نیز کمک میکنند.
در این بخش از مطلب مجله فرادرس میخواهیم نمونههایی از نِستِدفانکشن یا همان توابع تو در تو در پایتون را با هم مرور کنیم.
در زیر، مثالی از توابع تو در تو آورده شده است.
def outer_function(x):
def ier_function(y):
return x + y
return ier_function
add_five = outer_function(5)
print(add_five(3))
خروجی این کدها را در ادامه آوردهایم.
8
در این مثال، ۲ تابع به نامهای آورده شده در زیر تعریف کردهایم.

تابع outer_function u200aآرگومانی ورودی بهنام x u200aرا دریافت کرده و تابع ier_function u200aرا بهعنوان خروجی برمیگرداند. بههمین ترتیب، تابع ier_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 ier_function():
y = 2
return x + y
return ier_function()
print(outer_function())
خروجی این کدها را در ادامه آوردهایم.
3
در این مثال، تابعی بهنام outer_function تعریف کردهایم که مقدار اولیه 1 u200aرا به x نسبت میدهد و خروجی ier_function را بر میگرداند. ier_function متغیر y را با 2 u200aمقداردهی میکند و مجموع x و y را بر میگرداند.
زمانیکه تابع outer_function را فراخوانی میکنیم مقدار 3 u200aرا بهعنوان نتیجه، دریافت خواهیم کرد که مجموع متغیرهای x و y است. تابع ier_function درون محدوده outer_function فراخوانی میشود و به متغیر x - تعریف شده درون تابع outer_function - دسترسی خواهد داشت.
بهکارگیری توابع تو در تو در پایتون دارای مزیتهای بسیاری است. این قابلیت به برنامهنویسان امکان میدهد تا ساختار برنامهنویسی تطبیقپذیر و قویتری را ایجاد کنند، خوانایی کدهایشان را افزایش دهند و با ایجاد کدهای ماژولار، فرایند نگهداری از آن را تسهیل کنند.

«کپسولهسازی و ماژولار بودن» (Encapsulation and Modularity): مهمترین مزیت توابع تو در تو در پایتون، به توانایی آن در تعریف توابع کمکی درون محدوده خاص یک تابع متکی است. در نتیجه این کار، ضمن ترویج سازماندهی کدها، از بینظمی و شلوغی Namespace عمومی پیشگیری میشود. برای نمونه، مثال زیر را در نظر میگیریم.
def double_odd_numbers(numbers):
def is_odd(num):
return num % 2 != 0
def double(num):
return num * 2
return [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
return result
return 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 متفاوت را تسهیل میکنند.
با بهرهگیری از توابع تو در تو در پایتون، توسعهدهندگان این زبان میتوانند خوانایی و ماژولار بودن کدهای خود را افزایش دهند و از عملکردهای قدرتمند بستاری برای ایجاد ساختارهای متنوع و کارآمد تر استفاده کنند.

توابع تو در تو در پایتون به فرایند ایجاد یا همان تعریف تابعی درون تابعی دیگر اشاره دارد. این روند به سازماندهی بهتر و افزایش خوانایی کدها کمک بهسزایی میکند. برای ایجاد یک تابع تو در تو در پایتون، کافی است تا مراحل آورده شده در ادامه را دنبال کنیم.
همانطور که پیشتر هم بیان کردیم، ایجاد توابع تو در تو در پایتون، روش مفیدی برای سازماندهی و سادهسازی کدها محسوب میشود. همچنین، فرایندهای پیچیده را ساده میسازد و به خوانایی بهتر کدها نیز کمک میکند.
Nested Function-ها توابعی هستند که درون توابع دیگر تعریف شدهاند. ایجاد توابع به این شکل در برنامهنویسی، کاربرد زیادی دارد و میتواند در کاربردهای واقعی پایتون مورد استفاده قرار گیرد. بهطور مثال، یک تابع تو در تو میتواند تابعی را تعریف کرده که تابع دیگری را فراخوانی میکند. یا در مثالی دیگر یک تابع تو در تو میتواند تابعی را تعریف کرده که از تابع از پیشتعریف شدهای استفاده میکند. افزون بر این، تابع تو در تو میتواند «محدوده محلی» (Local Scope) را نیز در اختیارمان قرار دهد.
کدهای آورده شده در ادامه را در نظر بگیرید.
def parent_function(x):
def child_function(y):
return y * 2
return 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 ier(x):
return x + a
return ier
x = adder(3)
y = adder(5)
print(x(5))
print(y(5))
در این مثال، ier u200aیک تابع تو در تو است که درون تابع adder u200aتعریف شده است. تابع adder پارامتری بهنام a u200aرا دریافت و تابع ier را بر میگرداند. تابع ier پارامتری بهنام x u200aرا دریافت و مجموع x و a را بر میگرداند. هنگامیکه adder(3) u200aرا فراخوانی میکنیم، تابع ier را دریافت خواهیم کرد. ier را نیز بهعنوان x ذخیره میکنیم. این مورد برای adder(5) u200aهم صدق میکند که آن را بهعنوان y u200aذخیره میکنیم. هنگامیکه x(5) u200aباشد، نتیجهای برابر با 8 u200aخواهیم داشت و زمانیکه y(5) u200aفراخوانی میکنیم، عدد 10 u200aرا بهعنوان خروجی دریافت خواهیم کرد.
در ادامه این مطلب از مجله فرادرس، مثال دیگری را بررسی میکنیم.
def exponential(x):
def square(y):
return y * y
return 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 ier_power(power):
return num ** power
return ier_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 ier_function(num):
return num + i
functions.append(ier_function)
return 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
return num
return nested_func()
اکنون که دانستیم توابع تو در تو در پایتون چیست و چگونه نوشته میشود و همچنین کارکرد آنها چگونه است، برخی از پرسشهای رایج در رابطه با آن را نیز در این قسمت پاسخ میدهیم.
همانطور که گفتیم، توابع تو در تو شامل تعریف یک تابع درون تابع دیگر است که این قضیه به کپسولهسازی و سازماندهی کدها کمک خواهد کرد.

«توابع تو در تو» (Nested functions)، در واقع توابعی هستند که درون تابعی دیگر تعریف شدهاند.این توابع تنها از درون تابع در برگیرنده بیرونی قابل دسترسیاند. از سویی دیگر، «توابع ناشناس» (Anonymous Functions) را داریم که توابعی بدوننام هستند و با کلمه کلیدی lambda تعریف میشوند. این نوع توابع را میتوان در هر جایی از برنامه تعریف کرد و همچنین میتوانند بهعنوان آرگومان به تابع دیگر ارسال شوند.
در این مطلب از مجله فرادرس به توضیح این مفهوم پرداختیم که توابع تو در تو در پایتون چیست و نحوه ایجاد این نوع توابع چگونه است. همچنین با مزایی که این روش برایمان فراهم میکند آشنا شدیم. همچنین، ضمن اینکه مثالهای متعددی را در مورد توابع تو در تو در پایتون بیان کردیم، کاربردهای واقعی استفاده از آن را نیز به همراه کدهای مرتبط توضیح دادیم.
هنگام نوشتن توابع تو در تو ممکن است با خطاهایی روبهرو شویم که برای رفع آنها نیز نکاتی را بیان کردیم. در آخر نیز به بیان برخی از پرسشهای متداول در این بلاره پرداختیم و پاسخهای مربوطه را با هم مرور کردیم.
برچسب:
نویسنده: خنجی