خانه / آموزش‌ها / آموزش جامع Weakref و مدیریت حافظه در پایتون

آموزش جامع Weakref و مدیریت حافظه در پایتون

🐍 HomeOfPython
|
📅 1404/10/17

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

در پایتون، مدیریت حافظه به صورت خودکار توسط Garbage Collector (زباله‌روب) و مکانیزم Reference Counting (شمارش ارجاع) انجام می‌شود. برای درک ماژول weakref، ابتدا باید بدانیم پایتون چگونه تصمیم می‌گیرد یک آبجکت را از حافظه پاک کند.

مفهوم ارجاع قوی (Strong Reference) و چرخه عمر اشیاء

به طور پیش‌فرض، هرگاه شما متغیری را به یک آبجکت اختصاص می‌دهید، یک ارجاع قوی (Strong Reference) ایجاد می‌کنید. تا زمانی که حداقل یک ارجاع قوی به یک آبجکت وجود داشته باشد، پایتون آن را از حافظه پاک نمی‌کند.

چرخه عمر ارجاع قوی

مثال ۱: رفتار پیش‌فرض (Strong Reference)

در این مثال می‌بینیم که تا وقتی متغیر obj به کلاس اشاره دارد، کلاس پاک نمی‌شود (متد __del__ صدا زده نمی‌شود).

Python

مفهوم ارجاع ضعیف (Weak Reference) چیست؟

ماژول weakref به شما اجازه می‌دهد به یک آبجکت اشاره کنید بدون اینکه شمارنده ارجاع (Reference Count) آن را افزایش دهید. این یعنی اگر تمام ارجاع‌های قویِ یک آبجکت حذف شوند، حتی اگر شما هنوز یک ارجاع ضعیف (weakref) به آن داشته باشید، پایتون آن آبجکت را پاک می‌کند. ارجاع ضعیف شما پس از پاک شدن آبجکت، مقدار None برمی‌گرداند.

کاربردهای اصلی:

  1. پیاده‌سازی کش (Cache).
  2. جلوگیری از ارجاع‌های دایره‌ای (Circular References).

مثال ۲: ساخت اولین Weak Reference

برای ساخت ارجاع ضعیف از weakref.ref استفاده می‌کنیم. توجه کنید که برای دسترسی به آبجکت اصلی، باید ارجاع ضعیف را مانند یک تابع صدا بزنید ().

Python

مثال ۳: بررسی زنده بودن آبجکت

گاهی نیاز دارید فقط چک کنید آیا آبجکت هنوز در حافظه هست یا خیر.

Python

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

در سطح حرفه‌ای، weakref ابزاری حیاتی برای بهینه‌سازی مصرف حافظه در برنامه‌های بزرگ، مدیریت کش‌های هوشمند و کار با اشیاء سنگین است. در اینجا با Proxy‌ها، دیکشنری‌های ضعیف و Callbacks آشنا می‌شویم.

۱. استفاده از پروکسی‌ها (weakref.proxy)

استفاده از weakref.ref نیازمند فراخوانی () برای هر بار دسترسی است. weakref.proxy یک رابط راحت‌تر ایجاد می‌کند که دقیقاً مانند آبجکت اصلی رفتار می‌کند، اما همچنان ارجاع ضعیف است. تفاوت مهم: اگر آبجکت اصلی پاک شود، دسترسی به پروکسی باعث خطای ReferenceError می‌شود (برخلاف ref که None برمی‌گرداند).

مثال ۴: تفاوت Proxy و Ref

Python

۲. مجموعه‌های ضعیف (Weak Collections)

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

  • WeakValueDictionary: کلیدها قوی هستند، اما مقادیر (Values) ارجاع ضعیف‌اند. (عالی برای کش‌سازی).
  • WeakKeyDictionary: کلیدها ارجاع ضعیف هستند. (برای متصل کردن داده اضافه به یک آبجکت بدون تغییر آن).
  • WeakSet: مجموعه‌ای از ارجاع‌های ضعیف.

ساختار WeakValueDictionary

مثال ۵: پیاده‌سازی Cache خودکار با WeakValueDictionary

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

Python

۳. مدیریت Callback هنگام حذف (weakref.finalize)

به جای استفاده از متد مخرب __del__ (که می‌تواند باعث مشکلات در چرخه زباله‌روبی شود)، روش مدرن و حرفه‌ای استفاده از weakref.finalize است. این متد اجازه می‌دهد وقتی یک آبجکت garbage collect شد، یک تابع خاص اجرا شود.

مثال ۶: ثبت پاک‌سازی منابع (Cleanup)

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

python
# Static Snippet: Syntax definition
# weakref.finalize(obj, func, *args, **kwargs)
Python

۴. محدودیت‌ها و نکات فنی (Technical Limitations)

همه آبجکت‌ها در پایتون قابلیت داشتن ارجاع ضعیف را ندارند.

  • انواع داخلی مثل list, dict, tuple به صورت مستقیم از weakref پشتیبانی نمی‌کنند (مگر اینکه از آن‌ها ارث‌بری کنید).
  • کلاس‌هایی که __slots__ دارند باید حتماً اسلات __weakref__ را اضافه کنند.

مثال ۷: افزودن قابلیت Weakref به کلاس‌های با Slots

Python

مثال ۸: ارث‌بری برای انواع داخلی (Built-in Types)

برای ایجاد ارجاع ضعیف به یک دیکشنری یا لیست، باید یک زیرکلاس (Subclass) ایجاد کنید.

Python