خانه / آموزش‌ها / آموزش جامع کلوژر (Closure) در پایتون

آموزش جامع کلوژر (Closure) در پایتون

🐍 HomeOfPython
|
📅 1404/10/22

سطح مقدماتی (Beginner Level)

برای درک مفهوم کلوژر (Closure)، ابتدا باید با نحوه کارکرد توابع تودرتو (Nested Functions) و قلمرو متغیرها (Scope) آشنا باشیم. کلوژر یکی از مفاهیم قدرتمند پایتون است که به یک تابع اجازه می‌دهد تا به متغیرهای محیطی که در آن تعریف شده است، دسترسی داشته باشد، حتی اگر اجرای تابع بیرونی به پایان رسیده باشد.

۱. تابع تودرتو (Nested Function) چیست؟

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

python
# تعریف تابع بدون اجرا (Static)
def outer_function(message):
    # این متغیر متعلق به تابع بیرونی است
    text = message
    
    def inner_function():
        # تابع داخلی به متغیر text دسترسی دارد
        print(text)

    # تابع بیرونی، تابع داخلی را صدا می‌زند
    inner_function()

۲. تعریف کلوژر (Closure)

کلوژر زمانی شکل می‌گیرد که:

  1. یک تابع تودرتو داشته باشیم.
  2. تابع داخلی به متغیرهای تابع بیرونی (Non-local) ارجاع دهد.
  3. تابع بیرونی، خودِ تابع داخلی را (بدون پرانتز) برگرداند (Return کند).

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

مثال اول: ساخت یک کلوژر ساده

در این مثال، تابع multiplier یک عدد را می‌گیرد و یک تابع جدید تولید می‌کند که همیشه ورودی خود را در آن عدد ضرب می‌کند.

Python

مثال دوم: ذخیره وضعیت (State Retention)

کلوژرها می‌توانند جایگزین ساده‌ای برای کلاس‌ها باشند زمانی که می‌خواهید مقداری داده را در حافظه نگه دارید.

Python

سطح پیشرفته (Professional Level)

در سطح حرفه‌ای، باید بدانیم پایتون چگونه این متغیرها را مدیریت می‌کند و چه زمانی استفاده از کلوژر بهینه‌تر از کلاس یا روش‌های دیگر است. همچنین مشکلات رایج مثل Late Binding را بررسی می‌کنیم.

۱. کالبدشکافی کلوژر (__closure__ و cell objects)

در پایتون، توابع آبجکت هستند. وقتی یک تابع کلوژر ایجاد می‌کند، متغیرهای آزاد (Free Variables) در ویژگی خاصی به نام __closure__ ذخیره می‌شوند. این ویژگی حاوی تاپلی از سلول‌ها (Cells) است.

Python

۲. مشکل Late Binding (دام حلقه‌ها)

یکی از خطاهای رایج هنگام استفاده از کلوژرها یا توابع لامبدا در حلقه‌ها، پدیده Late Binding است. پایتون متغیرها را بر اساس نام جستجو می‌کند، نه بر اساس مقدار لحظه‌ای آن‌ها در زمان تعریف.

کد مشکل‌دار:

python
# Static: This code has a logical bug
def create_multipliers():
    multipliers = []
    for i in range(3):
        # تابع داخلی به i ارجاع می‌دهد، اما i تغییر می‌کند
        def func(x):
            return x * i
        multipliers.append(func)
    return multipliers

# وقتی توابع را اجرا کنیم، همه آن‌ها آخرین مقدار i (یعنی 2) را می‌بینند!
# funcs = create_multipliers()
# funcs[0](10) -> 20 (انتظار 0 بود)

راه‌حل حرفه‌ای (استفاده از Default Argument):

برای حل این مشکل، باید مقدار لحظه‌ای را به عنوان یک آرگومان پیش‌فرض به تابع پاس دهیم تا در زمان تعریف (Definition Time) ارزیابی شود.

Python

۳. کلوژر در مقابل کلاس (Performance & Clean Code)

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

مقایسه کلاس و کلوژر

Python

نکات کلیدی فنی

  1. حافظه: متغیرهای داخل کلوژر تا زمانی که خود تابع inner زنده است، توسط Garbage Collector پاک نمی‌شوند.
  2. تغییر مقادیر: اگر متغیر immutable باشد (مثل عدد یا رشته)، برای تغییر آن در تابع داخلی حتماً باید از nonlocal استفاده کنید. اگر mutable باشد (مثل لیست)، نیازی به nonlocal برای تغییر محتویات لیست نیست (اما برای انتساب مجدد لیست نیاز است).