توابع تو در تو در پایتون – آموزش به زبان ساده + مثال و کد – فرادرس

توابع تو در تو در پایتون – آموزش به زبان ساده + مثال و کد – فرادرس


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

فهرست مطالب این نوشته

مقدمه‌ای بر توابع در پایتون

در این قسمت، به‌طور مختصر مروری بر مفاهیم اولیه این موضوع، نظیر تابع در پایتون و برنامه‌نویسی تابعی خواهیم داشت.

توابع در پایتون

«توابع» (Functions) نقش مهمی را در برنامه‌نویسی به زبان پایتون بر عهده دارند. فانکشن‌ها در واقع قطعه کدهایی با قابلیت استفاده مجدد هستند که می‌توانند وظایف مشخصی را انجام دهند. پس از تعریف تابع، با استفاده از نام آن و – در صورت لزوم – ارسال آرگومان‌هایی در پرانتز، می‌توانیم آن را فراخوانی کنیم. برای انجام وظایف مختلف می‌توانیم توابع متعددی را تعریف کنیم که هر یک وظیفه خاص خود را دارند. با این کار کدهایمان راحت‌تر سازمان‌دهی و ساختارمند می‌شوند. مستند‌سازی و تایپ‌دهی تابع، مؤلفه‌های مهمی برای خوانایی کدها و دیباگ راحت‌تر آن به‌شمار می‌روند، به‌خصوص هنگامی‌که با پروژه‌های بزرگ سر و کار داریم.

برنامه نویسی تابعی

زبان برنامه‌نویسی پایتون از پارادایم‌ها یا الگوهای برنامه‌نویسی متعددی نظیر «برنامه‌نویسی تابعی» (Functional Programming) پشتیبانی می‌کند. این رویکرد برنامه‌نویسی به استفاده از توابع خالص، بدون استفاده از وضعیت مشترک، داده‌های «تغییرپذیر» (Mutable) و «اثرات ناخواسته» (Side-Effects) معطوف است. به‌طور معمول این رویکرد در پایتون به‌وسیله به‌کارگیری توابع «مرتبه‌بالاتر» (Higher-Order) و عبارات لامبدا یا lambda

 مورد استفاده قرار می‌گیرد.

منظور از توابع تو در تو در پایتون چیست؟

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

چه زمانی از توابع تو در تو در پایتون استفاده می کنیم؟

توابع تو در تو در پایتون زمانی‌ مفید هستند که نیازمند تعریف تابع کمکی هستیم که تنها داخل محدوده «تابع بیرونی» (Outer Function) مورد نیاز است. توابع تو در تو در پایتون افزون بر اینکه خوانایی کدهایمان را افزایش می‌دهند، به سازمان‌دهی و ماژولارسازی کدها نیز کمک می‌کنند.

مثال توابع تو در تو در پایتون

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

مثال اول از توابع تو در تو در پایتون

در زیر،‌ مثالی از توابع تو در تو آورده شده است.

1def outer_function(x):
2    def inner_function(y):
3        return x + y
4    return inner_function
5
6add_five = outer_function(5)
7print(add_five(3))

خروجی این کدها را در ادامه آورده‌ایم.

8

توضیح کدها

در این مثال، ۲ تابع به نام‌های آورده شده در زیر تعریف کرده‌ایم.

  • outer_function
  • inner_function

تابع outer_function

 آرگومانی ورودی به‌نام x

 را دریافت کرده و تابع inner_function

 را به‌عنوان خروجی برمی‌گرداند. به‌همین ترتیب، تابع inner_function

آرگومان y

 را دریافت کرده و مجموع x

و y

 را بر می‌گرداند.

خروجی تابع outer_function(5)

 را به متغیر add_five

 تخصیص می‌دهیم که تبدیل به تابعی شده و مقدار 5

 را به آرگومان خود اضافه می‌کند. هنگامی‌که add_five(3)

 را فراخوانی می‌کنیم، نتیجه‌ای برابر با 8

 دریافت خواهیم کرد.

مثال دوم از توابع تو در تو در پایتون

در زیر، مثال دیگری از توابع تو در تو را بررسی می‌کنیم.

1def outer_function():
2    x = 1
3    def inner_function():
4        y = 2
5        return x + y
6    return inner_function()
7
8print(outer_function())

خروجی این کدها را در ادامه آورده‌ایم.

3

توضیح کدها

در این مثال، تابعی به‌نام outer_function

تعریف کرده‌ایم که مقدار اولیه 1

 را به x

نسبت می‌دهد و خروجی inner_function

را بر می‌گرداند. inner_function

متغیر y

را با 2

 مقداردهی می‌کند و مجموع x

و y

را بر می‌گرداند.

زمانی‌که تابع outer_function

را فراخوانی می‌کنیم مقدار 3

 را به‌عنوان نتیجه، دریافت خواهیم کرد که مجموع متغیرهای x

و y

است. تابع inner_function

درون محدوده outer_function

فراخوانی می‌شود و به متغیر x

– تعریف شده درون تابع outer_function

– دسترسی خواهد داشت.

مزایای استفاده از توابع تو در تو در پایتون

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

«کپسوله‌سازی و ماژولار بودن» (Encapsulation and Modularity): مهم‌ترین مزیت توابع تو در تو در پایتون، به توانایی آن در تعریف توابع کمکی درون محدوده خاص یک تابع متکی است. در نتیجه این کار، ضمن ترویج سازمان‌دهی کدها، از بی‌نظمی و شلوغی Namespace عمومی پیشگیری می‌شود. برای نمونه، مثال زیر را در نظر می‌گیریم.

1def double_odd_numbers(numbers):
2    def is_odd(num):
3        return num % 2 != 0
4    
5    def double(num):
6        return num * 2
7    
8    return (double(num) for num in numbers if is_odd(num))

در این مثال، double_odd_numbers

 توابع is_odd

 و double

 را در بر می‌گیرد که درک آن را آسان می‌کند چون این توابع تنها در محدوده تابع اصلی استفاده می‌شوند.

«ایجاد بستار» (Closure Creation): مزیت قابل توجه دیگری که توابع تو در تو در پایتون برایمان فراهم می‌کنند، توانایی آن‌ها در ایجاد بستارها است. این قابلیت به توابع تو در تو امکان می‌دهد تا به متغیر‌ها، از تابع دربرگیرنده خود دسترسی پیدا کرده و تغییرات مربوطه را روی آن‌ها اعمال کنند. برای مثال، قطعه کدهای زیر را در نظر می‌گیریم.

1def power_function(base):
2    def exponent_power(exponent):
3        result = 1
4        for _ in range(exponent):
5            result *= base
6        return result
7    
8    return exponent_power
9
10square = power_function(2)
11cube = power_function(3)
12
13print(square(3))
14print(cube(2))

خروجی این کدها به صورت زیر خواهد بود.

8
9

در این حالت، تابع power_function

 تابع جدیدی به‌نام exponent_power

 ایجاد می‌کند که می‌تواند مقدار توان یک پایه base

 - به توان داده‌شده – را محاسبه کند. با به‌کارگیری این ساختار تو در تو، توابعی مانند square

 و cube

 به متغیر base

 از تابع دربرگیرنده، دسترسی پیدا کرده و ایجاد توابع جدید با مقادیر base

متفاوت را تسهیل می‌کنند.

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

ایجاد توابع تو در تو در پایتون چگونه است؟

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

  1. «تابع بیرونی» (Outer Function) را می‌سازیم.
  2. «تابع درونی» (Inner Function) را داخل تابع بیرونی تعریف می‌کنیم.
  3. تابع درونی را داخل تابع بیرونی فراخوانی می‌کنیم یا – به عنوان نتیجه آن – بر می‌گردانیم.

همان‌طور که پیش‌تر هم بیان کردیم، ایجاد توابع تو در تو در پایتون، روش مفیدی برای سازمان‌دهی و ساده‌سازی کدها محسوب می‌شود. همچنین، فرایندهای پیچیده را ساده می‌سازد و به خوانایی بهتر کدها نیز کمک می‌کند.

مثال های توابع تو در تو پایتون در کاربردهای واقعی

Nested Function-ها توابعی هستند که درون توابع دیگر تعریف شده‌اند. ایجاد توابع به این شکل در برنامه‌نویسی، کاربرد زیادی دارد و می‌تواند در کاربردهای واقعی پایتون مورد استفاده قرار گیرد. به‌طور مثال،‌ یک تابع تو در تو می‌تواند تابعی را تعریف کرده که تابع دیگری را فراخوانی می‌کند. یا در مثالی دیگر یک تابع تو در تو می‌تواند تابعی را تعریف کرده که از تابع از پیش‌تعریف ‌شده‌ای استفاده می‌کند. افزون بر این،‌ تابع تو در تو می‌تواند «محدوده محلی» (Local Scope) را نیز در اختیارمان قرار دهد.

مثال اول

کدهای آورده شده در ادامه را در نظر بگیرید.

1def parent_function(x):
2    def child_function(y):
3        return y * 2
4    return x + child_function(x)
5
6print(parent_function(5))

در این مثال،‌ تابع child_function

 یک تابع تو در تو محسوب می‌شود که درون تابع parent_function

 تعریف شده است. تابع parent_function

پارامتری به‌نام x

 را دریافت می‌کند. سپس از تابع child_function

برای دوبرابر کردن مقدار آن استفاده می‌کند. در نهایت، مجموع x

و child_function

را بر می‌گرداند. با اجرای parent_function(5)

 مقدار 15

 به عنوان نتیجه دریافت می‌کنیم.

مثال دوم

مثال دیگری در این رابطه آورده‌ایم.

1def adder(a):
2    def inner(x):
3        return x + a
4    return inner
5
6x = adder(3)
7y = adder(5)
8print(x(5))
9print(y(5))

در این مثال، inner

 یک تابع تو در تو است که درون تابع adder

 تعریف شده است. تابع adder

پارامتری به‌نام a

 را دریافت و تابع inner

را بر می‌گرداند. تابع inner

پارامتری به‌نام x

 را دریافت و مجموع x

و a

را بر می‌گرداند. هنگامی‌که adder(3)

 را فراخوانی می‌کنیم، تابع inner

را دریافت خواهیم کرد. inner

را نیز به‌عنوان x

ذخیره می‌کنیم. این مورد برای adder(5)

 هم صدق می‌کند که آن را به‌عنوان y

 ذخیره می‌کنیم. هنگامی‌که x(5)

 باشد، نتیجه‌ای برابر با 8

 خواهیم داشت و زمانی‌که y(5)

 فراخوانی می‌کنیم، عدد 10

 را به‌عنوان خروجی دریافت خواهیم کرد.

مثال سوم

در ادامه این مطلب از مجله فرادرس، مثال دیگری را بررسی می‌کنیم.

1def exponential(x):
2    def square(y):
3        return y * y
4    return square(x) * square(x)
5
6print(exponential(2))

در این مثال، تابع square

 یک تابع تو در تو است که درون تابع exponential

 تعریف شده است. تابع exponential

پارامتری به‌نام x

را دریافت کرده و مقدار مربع x

به توان چهارم را برمی‌گرداند. تابع square

پارامتری به‌نام y

را دریافت کرده و مربع y

را بر می‌گرداند. با اجرای exponential(2)

 ، مقدار 16

 را به‌عنوان نتیجه دریافت خواهیم کرد.

بهترین روش ها برای استفاده از توابع تو در تو در پایتون

بهترین روش‌ها برای این توابع تو در تو شامل موراد زیر است.

  • پرهیز از زیاده‌روی در تو در تو سازی
  • اطمینان از اینکه هر تابع، هدف واضح و مشخصی دارد.
  • استفاده از محدوده متغیر مناسب.

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

1# Example 1: Power function using nested functions
2def power_function(num):
3    def inner_power(power):
4        return num ** power
5    return inner_power
6
7# Example usage
8square_function = power_function(2)
9cube_function = power_function(3)
10print(square_function(5))  # Output: 32
11print(cube_function(5))  # Output: 243

در این مثال، تابع Power به‌صورت تو در تو ایجاد شده است. تابع بیرونی، عددی را دریافت کرده و تابع درونی را – که توان آن عدد را محاسبه می‌کند – به‌عنوان خروجی بر می‌گرداند. تابع درونی در محدوده تابع بیرونی تعریف شده است که به آن امکان می‌دهد به پارامتر num

 دسترسی داشته و توان را محاسبه کند.

مثال دیگری را در زیر آورده‌ایم.

1# Example 2: Functions in a loop
2def generate_functions():
3    functions = ()
4    for i in range(5):
5        def inner_function(num):
6            return num + i
7        functions.append(inner_function)
8    return functions
9
10# Example usage
11functions_list = generate_functions()
12for j, f in enumerate(functions_list):
13    print(f(j))  # Output: 4 5 6 7 8

در این مثال، با استفاده از یک حلقه و توابع تو در تو، لیستی از توابع تولید شده است. تابع درونی که داخل حلقه تعریف شده است، به آن امکان دسترسی به متغیر حلقه یعنی i

 را می‌دهد. لیست حاصل از توابع پس از آن می‌تواند برای اجرای محاسبات با مقادیر گوناگون i

مورد استفاده قرار گیرد.

خطاهای متداول هنگام استفاده از توابع تو در تو در پایتون

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

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

به‌طور مثال، کدهایی که در ادامه آورده‌ایم، خطای رایجی را نشان می‌دهد که متغیری در هر ۲ تابع والد و درونی تعریف شده است.

1def parent_func():
2    num = 2
3    def nested_func():
4        num = num * 2 # This will raise an UnboundLocalError when the function will be called
5        return num
6    return nested_func()

سوالات متداول

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

منظور از تابع تو در تو چیست؟

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

فرق بین توابع ناشناس و توابع تو در تو در پایتون چیست؟

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

جمع‌بندی

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

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